mirror of
https://gitee.com/johng/gf
synced 2026-06-12 12:13:22 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 992522342c | |||
| 040898cdc3 | |||
| 343126ef22 | |||
| 05760d1eac | |||
| c10f73f1f7 | |||
| 7e0fa8e0cd | |||
| 6fe6218505 | |||
| 6059782de8 |
@ -1,25 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/crypto/gaes"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gres"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
CryptoKey = []byte("x76cgqt36i9c863bzmotuf8626dxiwu0")
|
||||
)
|
||||
func Test() (int, int) {
|
||||
return 1, 1
|
||||
}
|
||||
|
||||
func Assert(v1, v2, v3 interface{}) {
|
||||
fmt.Println(v1)
|
||||
}
|
||||
|
||||
func F(v ...interface{}) []interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func main() {
|
||||
binContent, err := gres.Pack("public,config")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
binContent, err = gaes.Encrypt(binContent, CryptoKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := gfile.PutBytes("data.bin", binContent); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
Assert(F(Test()), 2, 3)
|
||||
}
|
||||
|
||||
348
RELEASE.2.MD
348
RELEASE.2.MD
@ -1,3 +1,351 @@
|
||||
# `v1.12.1` (2020-03-31)
|
||||
|
||||
大家好啊!久等啦!
|
||||
|
||||
由于自从上次版本的发布以来,越来越多小伙伴加入了`GF`的大家庭,并提供了许多不错的建议和反馈,这次版本对其中大部分反馈进行了处理,包括大部分的改进建议和部分新特性,因此这次的版本发布时隔了两个多月。`GF`非常注重代码质量以及可持续维护性,这次版本也进一步对框架大部分模块的示例、注释和单元测试用例进行了完善,目前单元测试用例数量约为`1991`例,代码覆盖率为`71%`,覆盖了所有模块的绝大部分主要功能。
|
||||
|
||||
`GF`框架提供了比较常用、高质量的基础开发模块,轻量级、模块化、高性能,推荐大家阅读框架源码了解更多细节。本次发布有个别的不兼容升级,往往批量替换即可,以下`change log`比较完善,建议升级前仔细阅读。
|
||||
|
||||
本次发布即意味下一版本开发计划的开启,欢迎更多小伙伴参与开源贡献:https://github.com/gogf/gf/projects/8
|
||||
|
||||
感谢大家支持!Enjoy your `GF`!
|
||||
|
||||
|
||||
# GoFrame
|
||||
|
||||
`GF(Go Frame)`是一款模块化、高性能、生产级的Go基础开发框架。实现了比较完善的基础设施建设以及开发工具链,提供了常用的基础开发模块,如:缓存、日志、队列、数组、集合、容器、定时器、命令行、内存锁、对象池、配置管理、资源管理、数据校验、数据编码、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信等等。并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、Middleware、服务注册、模板引擎等等,支持热重启、热更新、域名绑定、TLS/HTTPS、Rewrite等特性。
|
||||
|
||||
## 特点
|
||||
* 模块化、松耦合设计;
|
||||
* 模块丰富,开箱即用;
|
||||
* 简便易用,易于维护;
|
||||
* 社区活跃,大牛谦逊低调脾气好;
|
||||
* 高代码质量、高单元测试覆盖率;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 更适合企业及团队使用;
|
||||
|
||||
## 地址
|
||||
- 官网:https://goframe.org
|
||||
- 主库:https://github.com/gogf/gf
|
||||
- 码云:https://gitee.com/johng/gf
|
||||
|
||||
# Change Log
|
||||
|
||||
从`GF v1.12`版本开始,框架要求的最低`Golang`运行版本为`v1.13`,由于`Golang`新版本都是向后兼容的,因此推荐大家更新使用`Golang`新版本:https://golang.google.cn/dl/
|
||||
|
||||
> 本次版本也新增了`Swagger`的工具及插件支持,另行独立发布。
|
||||
|
||||
## `tool chain`
|
||||
1. `gen model`命令新增对`pgsql/mssql/sqlite/oracle`的模型生成支持。
|
||||
1. `gen model`命令生成模型新增公开包变量`Columns`用于获得表的字段名称。
|
||||
|
||||
## `net`
|
||||
1. `ghttp`
|
||||
- 注意:从该版本开始,`Server`默认关闭了平滑重启特性。开发者可以通过相应的配置选项打开。
|
||||
- 改进`Client.Get`方法,增加可选的请求参数。
|
||||
- 新增`Client`链式操作方法:`Header`, `HeaderRaw`, `Cookie`, `ContentType`, `ContentJson`, `ContentXml`, `Timeout`, `BasicAuth`, `Ctx`:https://goframe.org/net/ghttp/client/chain
|
||||
- 新增`Request.GetCtx/GetCtxVar/SetCtxVar/Context`上下文变量管理方法,用于请求内部的上下文变量特性:
|
||||
- 自定义变量:https://goframe.org/net/ghttp/request/custom
|
||||
- 上下文变量:https://goframe.org/net/ghttp/request/context
|
||||
- 新增`Request.GetUploadFile/GetUploadFiles`方法,以及`UploadFile`类型,极大简化文件上传处理逻辑:https://goframe.org/net/ghttp/client/demo/upload
|
||||
- 新增`Request.GetPage`方法,用于便捷地获得分页对象:
|
||||
- 基本介绍:https://goframe.org/util/gpage/index
|
||||
- 动态分页:https://goframe.org/util/gpage/dynamic
|
||||
- 静态分页:https://goframe.org/util/gpage/static
|
||||
- Ajax分页:https://goframe.org/util/gpage/ajax
|
||||
- URL模板:https://goframe.org/util/gpage/template
|
||||
- 自定义分页:https://goframe.org/util/gpage/custom
|
||||
- 改进`Response.Redirect*`方法,增加自定义的跳转HTTP状态码参数。
|
||||
- 改进`CORS`特性,完善跨域功能处理,并完全遵守`W3C`关于`OPTIONS`请求方法的规范约定:https://goframe.org/net/ghttp/cors
|
||||
- 模板视图对象增加`Request`内置变量,用于模板获得请求参数。由于`GF`框架的模板引擎采用两级缓存设计,减少`IO`开销的同时提升了执行效率,即使增加了大量的内置变量以及内置方法,经过大规模的性能测试,性能比其他`WebServer`库相同逻辑下高出`50% - 200%`的效率。
|
||||
- 新增`Server`实验性的`Plugin`特性。
|
||||
- 改进`Server`底层路由存储、检索逻辑,优化代码,提升效率。
|
||||
- 改进分组路由注册的源码位置记录功能,当路由注册冲突时能够精准定位及提示重复路由源码位置。
|
||||
- 改进`Server`日志处理。
|
||||
- 完善单元测试。
|
||||
|
||||
|
||||
## `database`
|
||||
1. `gdb`
|
||||
- 代码重构改进,增加`Driver`驱动接口设计,方便开发者自定义驱动实现。新增`Register`包方法,用于开发者注册自定义的数据库类型驱动:https://goframe.org/database/gdb/driver
|
||||
- 新增`GetArray`接口及实现,用于获取指定字段列的数据,构造成数组返回:https://goframe.org/database/gdb/chaining/select
|
||||
- 新增`InsertIgnore`接口及实现,用于写入时忽略写入冲突,仅对`mysql`数据库类型有效:https://goframe.org/database/gdb/chaining/insert-save
|
||||
- 新增`Schema`接口及实现,用于动态切换并获取指定名称的数据库对象:https://goframe.org/database/gdb/chaining/schema
|
||||
- 新增`FieldsStr/FieldsExStr`模型方法,用于获取表字段,并构造成字符串返回:hhttps://goframe.org/database/gdb/chaining/fields-retrieve
|
||||
- 新增`LockUpdate/LockShared`模型链式操作方法,用于实现悲观锁操作:https://goframe.org/database/gdb/chaining/lock
|
||||
- 改进`Where/Data`方法对更新参数输入方式的支持,提高灵活性:
|
||||
- https://goframe.org/database/gdb/chaining/select
|
||||
- https://goframe.org/database/gdb/chaining/update-delete
|
||||
- 查询结果对象`Result`新增`Array`方法,用于获得指定字段的数值,构造成数组返回:https://goframe.org/database/gdb/result
|
||||
- 改进`OmitEmpty`方法对`Data`输入参数的过滤,当给定的`Data`参数为空时间对象时,将会被过滤。
|
||||
- 增加默认的数据库连接池参数:`MaxIdleConns=10`。
|
||||
- 其他一些改进。
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gredis`
|
||||
- 增加/修改默认的数据库连接池参数:`MaxIdle=10`, `IdleTimeout=10s`, `MaxConnLifetime=30s`, `Wait=true`。
|
||||
- 完善单元测试。
|
||||
|
||||
## `container`
|
||||
1. 所有容器对象新增`UnmarshalValue(interface{}) error`接口方法实现,用于`gconv`转换时根据任意类型变量创建/设置对象内容,`GF`框架的所有容器对象均实现了该接口。
|
||||
|
||||
1. `garray`
|
||||
- 新增`RemoveValue`方法,用于根据数值检索并删除元素项。
|
||||
- 新增`FilterNil`方法,用于遍历并删除数组中的`nil`元素项。
|
||||
- 新增`FilterEmpty`方法,用于遍历并删除数组中的空值元素项,空值包括:`0, nil, false, "", len(slice/map/chan) == 0`。
|
||||
- 改进`Set/Fill/InsertBefore/InsertAfter`方法严谨性,将原有的链式操作返回值对象修改为`error`返回值。
|
||||
- 改进`Get/Remove/PopRand/PopLeft/PopRight/Rand`方法严谨性,增加`found`的`bool`返回值,标识当前方法是否有数据返回,当空数组或者操作越界时`found`返回值为`false`。
|
||||
- 改变`Rands`方法原有逻辑,保证按照给定大小返回随机数组。
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gpool`
|
||||
- 调整缓存池过期时间参数类型,旧版本为`int`类型表示毫秒,新版本为`time.Duration`类型使得时间控制更灵活。
|
||||
- 内部代码优化,性能改进。
|
||||
- 完善单元测试。
|
||||
- 完善注释。
|
||||
|
||||
## `os`
|
||||
1. `glog`
|
||||
- 增加`Rotation`日志滚动切分特性,新增按照文件大小或过期时间进行日志切分,并支持切分文件数量限制、对日志文件进行自动压缩、可自定义压缩级别(`1-9`)、支持对切分文件过期时间清理:https://goframe.org/os/glog/rotate
|
||||
- 新增`LevelPrefixes`特性,支持对日志级别的前缀名称进行自定义:https://goframe.org/os/glog/level
|
||||
- 新增`SetLevelStr`方法,并增加按照字符串进行日志级别配置的特性:
|
||||
- https://goframe.org/os/glog/level
|
||||
- https://goframe.org/os/glog/config
|
||||
- 新增`SetDefaultLogger`包方法,用于设置全局默认的`Logger`对象。
|
||||
|
||||
1. `gres`
|
||||
1. 改进资源内容编码设计,采用新的压缩算法,减少资源文件大小,例如原本`15MB`的网站静态资源文件(`css/js/html`等),资源文件打包后约为`4MB`左右:https://goframe.org/os/gres/index
|
||||
1. 注意:该改进与旧版本无法兼容,需要重新打包原有的资源文件。
|
||||
1. 完善单元测试。
|
||||
|
||||
1. `gcfg`
|
||||
- 去掉配置对象属性的原子并发安全控制,改为普通变量类型。由于配置管理是最常用模块之一,因此确保高效的设计及方法实现。
|
||||
- 单例对象做较大调整:为方便多文件场景下的配置文件调用,简便使用并提高开发效率,因此当给定的单例名称对应的`toml`配置文件在配置目录中存在时,将自动设置该单例对象的默认配置文件为该文件。例如:`g.Cfg("redis")`获取到的单例对象将会默认去检索并设置默认的配置文件为`redis.toml`,当该文件不存在时,则使用默认的配置文件(`config.toml`):https://goframe.org/net/ghttp/config
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gview`
|
||||
- 新增`concat`内置字符串拼接方法:https://goframe.org/os/gview/function/buildin
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gfile`
|
||||
- 改进`SelfPath`获取当前执行文件路径方法,提高执行效率。
|
||||
- 改进`Join`文件路径连接方法,防止多余的路径连接符号。
|
||||
- 改建`GetContents`文件内容获取方法执行效率,降低内存占用。
|
||||
- 新增`StrToSize`方法,用于将大小字符串转换为字节数字,大小字符串例如`10m`, `5KB`, `1.25Gib`等。
|
||||
- 新增`ReadLines/ReadByteLines`方法,用于按行读取指定文件内容,并给定读取回调函数。
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gtime`
|
||||
- 改进`gtime.Time`对象实现,统一字符串打印时间格式为`Y-m-d H:i:s`,如:`2020-01-01 12:00:00`。
|
||||
|
||||
1. `gcmd`
|
||||
- 命令行解析方法增加`strict`参数,用于设置当前解析是否严格解析,严格解析下如果给定了非法的选项,将会停止解析并返回错误。默认情况下为非严格解析。
|
||||
|
||||
1. `genv`
|
||||
- 改进`Remove`删除环境变量键值对方法,增加对多个键值对环境变量的删除。
|
||||
|
||||
1. `gfpool`
|
||||
- 改进代码实现,提高效率。
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gfsnotify`
|
||||
- 改进包初始化方法,当系统原因引起默认`Watcher`对象创建失败时,直接`panic`。
|
||||
|
||||
1. `gproc`
|
||||
- 改进`SearchBinaryPath`方法。
|
||||
- 改进`Process.Kill`方法在`windows`及`*niux`平台下不同表现的处理。
|
||||
|
||||
## `encoding`
|
||||
1. `gjson`
|
||||
- 代码改进、完善注释、新增大量代码示例。
|
||||
- 文档更新:
|
||||
- 基本介绍:https://goframe.org/encoding/gjson/index
|
||||
- 对象创建:https://goframe.org/encoding/gjson/object
|
||||
- 层级访问:https://goframe.org/encoding/gjson/pattern
|
||||
- Struct转换:https://goframe.org/encoding/gjson/conversion-struct
|
||||
- 动态创建修改:https://goframe.org/encoding/gjson/dataset
|
||||
- 数据格式转换:https://goframe.org/encoding/gjson/conversion-format
|
||||
|
||||
## `frame`
|
||||
1. `g`
|
||||
- 新增`IsNil`方法,用于判断当前给定的变量是否为`nil`,该方法有可能会使用到反射来实现判断。
|
||||
- 新增`IsEmpty`方法,用于判断当前给定的变量是否为`空`,该方法优先使用断言判断但有可能会使用到反射来实现判断。空值包括:`0, nil, false, "", len(slice/map/chan) == 0`。
|
||||
- 标记废弃`SetServerGraceful`方法,转而统一交给`Server`的配置来管理。
|
||||
1. `gins`
|
||||
- 改进代码结构,方便维护。
|
||||
- 改进、完善单元测试。
|
||||
1. `gmvc`
|
||||
- 新增`M`类型,为`*gdb.Model`的别名简称,用于工具链自动生成模型中的`M`属性。
|
||||
|
||||
## `text`
|
||||
1. `gstr`
|
||||
- 新增`HasPrefix/HasSuffix`方法。
|
||||
- 新增`OctStr`方法,用于将八进制字符串转换为其对应的`unicode`字符串,例如转换为中文。常用于`gRPC`底层通信编码中。
|
||||
- 完善单元测试。
|
||||
|
||||
## `debug`
|
||||
1. `gdebug`
|
||||
- 改进代码结构,方便维护。
|
||||
- 新增`TestDataPath`方法,用于当前包单元测试中获得当前包中`testdata`目录的绝对路径。
|
||||
|
||||
## `util`
|
||||
1. `gconv`
|
||||
- 改进`String`字符串转换方法,增加对`time.Time/*time.Time/gtime.Time`类型的内置支持。
|
||||
- 改进`Map/Struct`转换方法,增加对一些特殊场景的细节处理。经过大规模的使用,大量的反馈改进,不断完善了细节。
|
||||
- 改进`Struct`转换方法,增加对`UnmarshalValue(interface{}) error`接口的支持。
|
||||
- 完善单元测试。
|
||||
|
||||
1. `grand`
|
||||
- 注意:不兼容调整,原有的`Str`方法更名为`S`方法,用以获取指定长度的随机字符串、数字,并增加`symbol`参数,指定是否可以随机返回特殊可见字符。
|
||||
- 新增`Str`方法,用于从指定的字符串字符中随机获取指定长度的字符串。该方法同时支持`unicode`字符串,例如:中文:https://goframe.org/util/grand/index
|
||||
- 新增`Symbols`方法,用于随机返回指定场孤独的特殊可见字符:https://goframe.org/util/grand/index
|
||||
- 完善单元测试。
|
||||
|
||||
1. `gvalid`
|
||||
- 长度校验规则增加对`unicode`字符串的支持,例如:中文。
|
||||
|
||||
# Bug Fix
|
||||
1. 修复`Server`的视图对象配置失效问题。
|
||||
1. 修复`Server`中间件在中间件`panic`情况下,忽略`Middleware.Next`方法控制,导致鉴权中间件失效的问题。
|
||||
1. 修复`gudp.Server`在请求包大小超过`64bytes`时的断包问题,并调整默认缓冲区大小为`1024byte`,开发者可自定义缓冲区大小。
|
||||
1. 修复`gfile.MTimeMillisecond`方法返回错误的文件修改毫秒时间戳。
|
||||
1. 修复`gconv.Int64`对负数转换的支持。
|
||||
1. 其他一些修复。
|
||||
1. 详见:https://github.com/gogf/gf/issues?q=label%3Abug
|
||||
|
||||
|
||||
|
||||
# `v1.11.2` (2020-01-14)
|
||||
|
||||
`GF(Go Frame)` https://goframe.org 是一款模块化、高性能、生产级的Go基础开发框架。实现了比较完善的基础设施建设,包括常用的核心开发组件, 如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、资源管理、数据校验、数据编码、文件监控、 定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、并发安全容器等等。 并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、Middleware、服务注册、配置管理、模板引擎等等, 支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。
|
||||
|
||||
`GF`有着丰富的基础模块、完善的工具链、详尽的开发文档。开源近两年以来,`GF`得到越来越多小伙伴的肯定和支持,从寂寂无名到现在被广泛应用于微服务、物联网、区块链、电商系统、银行系统等企业级的生产项目中,经历了百万级、千万级项目的考验,2019年度被码云`gitee`评选为`GVP`最有价值开源项目。`GF`正在快速地成长中,目前保持着1-2个月迭代版本的发布规律,社区活跃,欢迎加入`GF`大家庭。
|
||||
|
||||
最后,祝大家2020新年快乐,鼠年大吉!
|
||||
|
||||
|
||||
|
||||
## 新特性
|
||||
|
||||
1. 新年新气象,官网文档大量更新:https://goframe.org/index
|
||||
1. `GF`工具链更新:https://goframe.org/toolchain/cli
|
||||
- 新增`gf run`热编译运行命令;
|
||||
- 新增`gf docker` Docker镜像编译命令;
|
||||
- 新增`gf gen model` 强大的模型自动生成命令;
|
||||
- `gf build`命令增加对配置文件配置支持;
|
||||
- 大量命令行工具改进工作;
|
||||
- 新增自动代理设置特性;
|
||||
1. 数据库`ORM`新特性:
|
||||
- 增加`prefix`数据表前缀支持:https://goframe.org/database/gdb/config
|
||||
- 新增`Schema`数据库对象并改进数据库切换特性:https://goframe.org/database/gdb/chaining/schema
|
||||
- 新增`WherePri`方法,用于自动识别主键的条件方法:https://goframe.org/database/gdb/chaining/select
|
||||
- 文档及示例大量更新,覆盖95%以上的功能特性;
|
||||
|
||||
|
||||
|
||||
## 功能改进
|
||||
|
||||
### `container`
|
||||
1. `garray`
|
||||
- 新增`New*ArrayRange`方法,用于初始化创建指定数值范围的数组。
|
||||
- 新增`Iterator*`方法,用于数组项元素回调遍历。
|
||||
- 完善单元测试。
|
||||
1. `gvar`
|
||||
- 改进`MapStrStr`、`MapStrStrDeep`方法实现。
|
||||
|
||||
### `net`
|
||||
1. `ghttp`
|
||||
- 改进HTTP客户端,增加对提交参数的自动`Content-Type`识别功能。
|
||||
- `Request`对象增加`Parse`方法,用于快捷的对象转换即参数校验。
|
||||
- `Request.GetPost*`方法全部标记为`deprecated`,统一客户端参数提交方式为`QueryString`, `Form`, `Body`。
|
||||
- 去掉`Response`模板解析时的`Get`/`Post`内置变量,新增`Query`, `Form`, `Request`内置变量:https://goframe.org/net/ghttp/response/template
|
||||
- 改进`Response.WriteJson*`及`Response.WriteXml*`方法,增加对`string`, `[]byte`类型参数的支持。
|
||||
- `Server`新增`GetRouterArray`方法,用于向应用层暴露并获取`Server`的路由列表。
|
||||
- `Server`新增`Use`方法,该方法为`BindMiddlewareDefault`的别名,用以全局中间件的注册。
|
||||
- `Server`新增`RouteOverWrite`配置项,用于控制是否在注册路由冲突时自动覆盖,默认关闭并提示。
|
||||
- `Server`新增`Graceful`配置项,用于在单服务场景下控制平滑重启特性的开启/关闭,默认开启。
|
||||
- 完善单元测试。
|
||||
1. `gtcp`
|
||||
- 改进简单协议下的数据包发送接收功能。
|
||||
- 将连接池默认的缓存过期时间`30`秒修改为`10`秒。
|
||||
- 完善单元测试。
|
||||
|
||||
### `database`
|
||||
1. `gdb`
|
||||
- 新增`As`数据表别名方法。
|
||||
- 改进数据表、字段的安全字符自动识别添加功能。
|
||||
- 新增`DB`数据库对象切换方法。
|
||||
- 新增`TX`链式操作事务支持方法。
|
||||
- 完善单元测试。
|
||||
### `os`
|
||||
1. `gcfg`
|
||||
- 新增`GetMapStrStr`方法。
|
||||
1. `gcmd`
|
||||
- 增加参数解析的`strict`严格参数,默认严格解析,不存在指定参数/选项名称时则报错返回。
|
||||
1. `genv`
|
||||
- 改进`Remove`方法支持多个环境变量的删除。
|
||||
1. `gfile`
|
||||
- 改进`TempDir`临时目录获取方法,在`*nix`系统下默认为`/tmp`目录。
|
||||
- 新增`ReadLines`, `ReadByteLines`方法,用以按行回调读取文件内容。
|
||||
- 新增`Copy*`方法,用以文件/目录的拷贝,支持递归。
|
||||
- 新增`Replace*`方法,用以目录下的文件内容替换,支持递归。
|
||||
- 改进`Scan*`方法,用以检索并返回指定目录下的所有文件/目录,支持文件模式指定,支持递归。
|
||||
- 完善单元测试。
|
||||
1. `gproc`
|
||||
- 改进命令行运行方法。
|
||||
- 改进`Shell`命令文件检索逻辑。
|
||||
- 改进实验性的进程间通信设计。
|
||||
1. `gtime`
|
||||
- 将包方法以及`Time`对象的时间戳方法`Second`, `Millisecond`, `Microsecond`, `Nanosecond`标记为废除,
|
||||
并新增`Timestamp`, `TimestampMilli`, `TimestampMicro`, `TimestampNano`替换。
|
||||
- 需要注意的是以上修改可能和老版本存在兼容性问题。
|
||||
|
||||
1. `gview`
|
||||
- 解析功能、缓存设计改进。
|
||||
- 新增`encode`, `decode`HTML编码/解码模板函数。
|
||||
- 新增`concat`字符串拼接模板函数。
|
||||
- 新增`dump`模板函数,功能类似于`g.Dump`方法。
|
||||
- 新增`AutoEncode`配置项,用于自动转码输出的`HTML`内容,常用于防止`XSS`,默认关闭。需要注意的是该特性并不会影响`include`内置函数: https://goframe.org/os/gview/xss
|
||||
- 单元测试完善。
|
||||
|
||||
### `crypto`
|
||||
1. `gmd5`
|
||||
- 增加`MustEncrypt`, `MustEncryptBytes`, `MustEncryptString`, `MustEncryptFile`方法。
|
||||
1. `gsha1`
|
||||
- 增加`MustEncryptFile`方法
|
||||
|
||||
### `encoding`
|
||||
1. `gbase64`
|
||||
- 新增`MustEncodeFile`, `MustEncodeFileToString`, `MustDecode`, `MustDecodeToString`方法。
|
||||
1. `gjson`/`gparser`
|
||||
- 新增`GetMapStrStr`方法。
|
||||
- 新增`Must*`方法,用于指定数据格式的转换失败时产生`panic`错误,而不会返回`error`参数。
|
||||
|
||||
### `util`
|
||||
1. `gconv`
|
||||
- 改进`Convert`方法增加对`[]int32`, `[]int64`, `[]uint`, `[]uint32`, `[]uint64`, `[]float32`, `[]float64`数据类型的转换支持。
|
||||
- 改进`String`字符串转换方法对指针参数的支持。
|
||||
- 改进`Map*` Map转换方法的代码结构及性能。
|
||||
- 新增`Floats`, `Float32s`, `Float64s`对`[]float32`, `[]float64`类型转换方法。
|
||||
- 新增`Ints`, `Int32s`, `Int64s`对`[]int`, `[]int32`, `[]int64`类型转换方法。
|
||||
- 新增`Uints`, `Uint32s`, `Uint64s`对`[]uint`, `[]uint32`, `[]uint64`类型转换方法。
|
||||
- 完善单元测试。
|
||||
|
||||
|
||||
### `frame`
|
||||
1. `gins`
|
||||
- 所有的单例对象在获取失败时产生`panic`错误。
|
||||
|
||||
## Bug Fix
|
||||
1. 增加对常见错误路由格式例如`/user//index`的兼容支持。
|
||||
1. 修复`gtcp`/`gudp`在数据接收时的间隔时间单位问题。
|
||||
1. 修复`gfile`/`gspath`/`gfsnotify`包对文件的存在性判断不严谨问题。
|
||||
1. 修复`gproc.Kill`方法在`windows`系统下的运行阻塞问题。
|
||||
1. 修复`gstr.TrimLeftStr`/`gstr.TrimRightStr`在被替换字符串长度小于替换字符串长度时的数组溢出问题。
|
||||
|
||||
|
||||
|
||||
# `v1.10.0` (2019-12-05)
|
||||
|
||||
各位`gfer`久等了,较上一次发布时间过去已有两个多月了,这段时间`GF`也在不断地迭代改进,细节比较多,拟了个大概,以下是`release log`。
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
> This markdown is deprecated and will be removed in future. All TODO features are staged in the issue: https://github.com/gogf/gf/issues
|
||||
|
||||
# ON THE WAY
|
||||
1. 增加图形验证码支持,至少支持数字和英文字母;
|
||||
1. Cookie&Session数据池化处理;
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// Array is a golang array with rich features.
|
||||
type Array struct {
|
||||
mu *rwmutex.RWMutex
|
||||
array []interface{}
|
||||
@ -94,21 +96,26 @@ func NewArrayFromCopy(array []interface{}, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *Array) Get(index int) interface{} {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *Array) Get(index int) (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return nil, false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Set sets value to specified index.
|
||||
func (a *Array) Set(index int, value interface{}) *Array {
|
||||
func (a *Array) Set(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
a.array[index] = value
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -154,48 +161,60 @@ func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
func (a *Array) InsertBefore(index int, value interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]interface{}{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *Array) InsertAfter(index int, value interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]interface{}{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
func (a *Array) Remove(index int) interface{} {
|
||||
func (a *Array) InsertBefore(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return nil
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency。
|
||||
rear := append([]interface{}{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *Array) InsertAfter(index int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *Array) Remove(index int) (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *Array) doRemoveWithoutLock(index int) (value interface{}, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return nil, false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
@ -226,64 +245,68 @@ func (a *Array) PushRight(value ...interface{}) *Array {
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
func (a *Array) PopRand() interface{} {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *Array) PopRand() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
func (a *Array) PopRands(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]interface{}, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
func (a *Array) PopLeft() interface{} {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *Array) PopLeft() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
func (a *Array) PopRight() interface{} {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *Array) PopRight() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
func (a *Array) PopLefts(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if length == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size > length {
|
||||
size = length
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
@ -294,12 +317,14 @@ func (a *Array) PopLefts(size int) []interface{} {
|
||||
func (a *Array) PopRights(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -529,11 +554,11 @@ func (a *Array) Merge(array interface{}) *Array {
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
func (a *Array) Fill(startIndex int, num int, value interface{}) *Array {
|
||||
func (a *Array) Fill(startIndex int, num int, value interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 {
|
||||
startIndex = 0
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -542,7 +567,7 @@ func (a *Array) Fill(startIndex int, num int, value interface{}) *Array {
|
||||
a.array[i] = value
|
||||
}
|
||||
}
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
@ -596,27 +621,27 @@ func (a *Array) Pad(size int, val interface{}) *Array {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *Array) Rand() interface{} {
|
||||
func (a *Array) Rand() (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *Array) Rands(size int) []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]interface{}, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]interface{}, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Shuffle randomly shuffles the array.
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// IntArray is a golang int array with rich features.
|
||||
type IntArray struct {
|
||||
mu *rwmutex.RWMutex
|
||||
array []int
|
||||
@ -77,21 +79,26 @@ func NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *IntArray) Get(index int) int {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *IntArray) Get(index int) (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return 0, false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Set sets value to specified index.
|
||||
func (a *IntArray) Set(index int, value int) *IntArray {
|
||||
func (a *IntArray) Set(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
a.array[index] = value
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -127,8 +134,7 @@ func (a *IntArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
// The parameter <reverse> controls whether sort in increasing order(default) or decreasing order.
|
||||
func (a *IntArray) Sort(reverse ...bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
@ -156,57 +162,68 @@ func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
func (a *IntArray) InsertBefore(index int, value int) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]int{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *IntArray) InsertAfter(index int, value int) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]int{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// Note that if the index is out of range of array, it returns 0.
|
||||
func (a *IntArray) Remove(index int) int {
|
||||
func (a *IntArray) InsertBefore(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return 0
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
rear := append([]int{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *IntArray) InsertAfter(index int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
rear := append([]int{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *IntArray) Remove(index int) (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *IntArray) doRemoveWithoutLock(index int) (value int, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return 0, false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *IntArray) RemoveValue(value int) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -229,72 +246,72 @@ func (a *IntArray) PushRight(value ...int) *IntArray {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, it returns 0.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *IntArray) PopLeft() int {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *IntArray) PopLeft() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, it returns 0.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *IntArray) PopRight() int {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *IntArray) PopRight() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *IntArray) PopRand() int {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *IntArray) PopRand() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopRands(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopLefts(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if length == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size > length {
|
||||
size = length
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
@ -302,15 +319,19 @@ func (a *IntArray) PopLefts(size int) []int {
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *IntArray) PopRights(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -535,11 +556,11 @@ func (a *IntArray) Merge(array interface{}) *IntArray {
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
func (a *IntArray) Fill(startIndex int, num int, value int) *IntArray {
|
||||
func (a *IntArray) Fill(startIndex int, num int, value int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 {
|
||||
startIndex = 0
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -548,7 +569,7 @@ func (a *IntArray) Fill(startIndex int, num int, value int) *IntArray {
|
||||
a.array[i] = value
|
||||
}
|
||||
}
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
@ -602,27 +623,27 @@ func (a *IntArray) Pad(size int, value int) *IntArray {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *IntArray) Rand() int {
|
||||
func (a *IntArray) Rand() (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *IntArray) Rands(size int) []int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]int, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Shuffle randomly shuffles the array.
|
||||
|
||||
@ -9,6 +9,8 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
"sort"
|
||||
@ -19,6 +21,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// StrArray is a golang string array with rich features.
|
||||
type StrArray struct {
|
||||
mu *rwmutex.RWMutex
|
||||
array []string
|
||||
@ -63,21 +66,26 @@ func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *StrArray) Get(index int) string {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *StrArray) Get(index int) (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return "", false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Set sets value to specified index.
|
||||
func (a *StrArray) Set(index int, value string) *StrArray {
|
||||
func (a *StrArray) Set(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
a.array[index] = value
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -142,57 +150,68 @@ func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
|
||||
}
|
||||
|
||||
// InsertBefore inserts the <value> to the front of <index>.
|
||||
func (a *StrArray) InsertBefore(index int, value string) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]string{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *StrArray) InsertAfter(index int, value string) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]string{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return a
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// Note that if the index is out of range of array, it returns an empty string.
|
||||
func (a *StrArray) Remove(index int) string {
|
||||
func (a *StrArray) InsertBefore(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return ""
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency。
|
||||
rear := append([]string{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the <value> to the back of <index>.
|
||||
func (a *StrArray) InsertAfter(index int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", index, len(a.array)))
|
||||
}
|
||||
rear := append([]string{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *StrArray) Remove(index int) (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *StrArray) doRemoveWithoutLock(index int) (value string, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return "", false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *StrArray) RemoveValue(value string) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -215,89 +234,92 @@ func (a *StrArray) PushRight(value ...string) *StrArray {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *StrArray) PopLeft() string {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *StrArray) PopLeft() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *StrArray) PopRight() string {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *StrArray) PopRight() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *StrArray) PopRand() string {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *StrArray) PopRand() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopRands(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]string, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopLefts(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if size > length {
|
||||
size = length
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *StrArray) PopRights(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -525,11 +547,11 @@ func (a *StrArray) Merge(array interface{}) *StrArray {
|
||||
|
||||
// Fill fills an array with num entries of the value <value>,
|
||||
// keys starting at the <startIndex> parameter.
|
||||
func (a *StrArray) Fill(startIndex int, num int, value string) *StrArray {
|
||||
func (a *StrArray) Fill(startIndex int, num int, value string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if startIndex < 0 {
|
||||
startIndex = 0
|
||||
if startIndex < 0 || startIndex > len(a.array) {
|
||||
return errors.New(fmt.Sprintf("index %d out of array range %d", startIndex, len(a.array)))
|
||||
}
|
||||
for i := startIndex; i < startIndex+num; i++ {
|
||||
if i > len(a.array)-1 {
|
||||
@ -538,7 +560,7 @@ func (a *StrArray) Fill(startIndex int, num int, value string) *StrArray {
|
||||
a.array[i] = value
|
||||
}
|
||||
}
|
||||
return a
|
||||
return nil
|
||||
}
|
||||
|
||||
// Chunk splits an array into multiple arrays,
|
||||
@ -592,27 +614,27 @@ func (a *StrArray) Pad(size int, value string) *StrArray {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *StrArray) Rand() string {
|
||||
func (a *StrArray) Rand() (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *StrArray) Rands(size int) []string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]string, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]string, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Shuffle randomly shuffles the array.
|
||||
|
||||
@ -22,6 +22,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// SortedArray is a golang sorted array with rich features.
|
||||
// It's using increasing order in default.
|
||||
type SortedArray struct {
|
||||
mu *rwmutex.RWMutex
|
||||
@ -148,38 +149,46 @@ func (a *SortedArray) Add(values ...interface{}) *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *SortedArray) Get(index int) interface{} {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedArray) Get(index int) (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return nil, false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
func (a *SortedArray) Remove(index int) interface{} {
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedArray) Remove(index int) (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *SortedArray) doRemoveWithoutLock(index int) (value interface{}, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
@ -193,50 +202,53 @@ func (a *SortedArray) RemoveValue(value interface{}) bool {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
func (a *SortedArray) PopLeft() interface{} {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedArray) PopLeft() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
func (a *SortedArray) PopRight() interface{} {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedArray) PopRight() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
func (a *SortedArray) PopRand() interface{} {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedArray) PopRand() (value interface{}, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
func (a *SortedArray) PopRands(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]interface{}, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
@ -245,13 +257,14 @@ func (a *SortedArray) PopRands(size int) []interface{} {
|
||||
func (a *SortedArray) PopLefts(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if size > length {
|
||||
size = length
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
return value
|
||||
@ -261,12 +274,14 @@ func (a *SortedArray) PopLefts(size int) []interface{} {
|
||||
func (a *SortedArray) PopRights(size int) []interface{} {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -554,27 +569,27 @@ func (a *SortedArray) Chunk(size int) [][]interface{} {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *SortedArray) Rand() interface{} {
|
||||
func (a *SortedArray) Rand() (value interface{}, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *SortedArray) Rands(size int) []interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]interface{}, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]interface{}, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// SortedIntArray is a golang sorted int array with rich features.
|
||||
// It's using increasing order in default.
|
||||
type SortedIntArray struct {
|
||||
mu *rwmutex.RWMutex
|
||||
@ -133,135 +134,145 @@ func (a *SortedIntArray) Add(values ...int) *SortedIntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *SortedIntArray) Get(index int) int {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedIntArray) Get(index int) (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return 0, false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// Note that if the index is out of range of array, it returns 0.
|
||||
func (a *SortedIntArray) Remove(index int) int {
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedIntArray) Remove(index int) (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedIntArray) RemoveValue(value int) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, it returns 0.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedIntArray) PopLeft() int {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedIntArray) PopLeft() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, it returns 0.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedIntArray) PopRight() int {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedIntArray) PopRight() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, it returns 0.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedIntArray) PopRand() int {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedIntArray) PopRand() (value int, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopRands(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopLefts(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if size > length {
|
||||
size = length
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedIntArray) PopRights(size int) []int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -555,27 +566,27 @@ func (a *SortedIntArray) Chunk(size int) [][]int {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *SortedIntArray) Rand() int {
|
||||
func (a *SortedIntArray) Rand() (value int, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *SortedIntArray) Rands(size int) []int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]int, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// SortedStrArray is a golang sorted string array with rich features.
|
||||
// It's using increasing order in default.
|
||||
type SortedStrArray struct {
|
||||
mu *rwmutex.RWMutex
|
||||
@ -118,39 +119,46 @@ func (a *SortedStrArray) Add(values ...string) *SortedStrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Get returns the value of the specified index,
|
||||
// the caller should notice the boundary of the array.
|
||||
func (a *SortedStrArray) Get(index int) string {
|
||||
// Get returns the value by the specified index.
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedStrArray) Get(index int) (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
return value
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return "", false
|
||||
}
|
||||
return a.array[index], true
|
||||
}
|
||||
|
||||
// Remove removes an item by index.
|
||||
// Note that if the index is out of range of array, it returns an empty string.
|
||||
func (a *SortedStrArray) Remove(index int) string {
|
||||
// If the given <index> is out of range of the array, the <found> is false.
|
||||
func (a *SortedStrArray) Remove(index int) (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(index)
|
||||
}
|
||||
|
||||
// doRemoveWithoutLock removes an item by index without lock.
|
||||
func (a *SortedStrArray) doRemoveWithoutLock(index int) (value string, found bool) {
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
// Determine array boundaries when deleting to improve deletion efficiency.
|
||||
if index == 0 {
|
||||
value := a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
} else if index == len(a.array)-1 {
|
||||
value := a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
// If it is a non-boundary delete,
|
||||
// it will involve the creation of an array,
|
||||
// then the deletion is less efficient.
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// RemoveValue removes an item by value.
|
||||
@ -164,89 +172,92 @@ func (a *SortedStrArray) RemoveValue(value string) bool {
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedStrArray) PopLeft() string {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedStrArray) PopLeft() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
value := a.array[0]
|
||||
value = a.array[0]
|
||||
a.array = a.array[1:]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRight pops and returns an item from the end of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedStrArray) PopRight() string {
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedStrArray) PopRight() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
index := len(a.array) - 1
|
||||
if index <= 0 {
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
value := a.array[index]
|
||||
value = a.array[index]
|
||||
a.array = a.array[:index]
|
||||
return value
|
||||
return value, true
|
||||
}
|
||||
|
||||
// PopRand randomly pops and return an item out of array.
|
||||
// Note that if the array is empty, it returns an empty string.
|
||||
// Be very careful when use this function in loop statement.
|
||||
// You can use IsEmpty() of Len() == 0 checks if this array empty.
|
||||
func (a *SortedStrArray) PopRand() string {
|
||||
return a.Remove(grand.Intn(len(a.array)))
|
||||
// Note that if the array is empty, the <found> is false.
|
||||
func (a *SortedStrArray) PopRand() (value string, found bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
|
||||
// PopRands randomly pops and returns <size> items out of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopRands(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
size = len(a.array)
|
||||
}
|
||||
array := make([]string, size)
|
||||
for i := 0; i < size; i++ {
|
||||
index := grand.Intn(len(a.array))
|
||||
array[i] = a.array[index]
|
||||
a.array = append(a.array[:index], a.array[index+1:]...)
|
||||
array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// PopLefts pops and returns <size> items from the beginning of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopLefts(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
length := len(a.array)
|
||||
if size > length {
|
||||
size = length
|
||||
}
|
||||
if size == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
if size >= len(a.array) {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[0:size]
|
||||
a.array = a.array[size:]
|
||||
return value
|
||||
}
|
||||
|
||||
// PopRights pops and returns <size> items from the end of array.
|
||||
// If the given <size> is greater than size of the array, it returns all elements of the array.
|
||||
// Note that if given <size> <= 0 or the array is empty, it returns nil.
|
||||
func (a *SortedStrArray) PopRights(size int) []string {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if len(a.array) == 0 {
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := len(a.array) - size
|
||||
if index < 0 {
|
||||
index = 0
|
||||
if index <= 0 {
|
||||
array := a.array
|
||||
a.array = a.array[:0]
|
||||
return array
|
||||
}
|
||||
value := a.array[index:]
|
||||
a.array = a.array[:index]
|
||||
@ -540,27 +551,27 @@ func (a *SortedStrArray) Chunk(size int) [][]string {
|
||||
}
|
||||
|
||||
// Rand randomly returns one item from array(no deleting).
|
||||
func (a *SortedStrArray) Rand() string {
|
||||
func (a *SortedStrArray) Rand() (value string, found bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.array[grand.Intn(len(a.array))]
|
||||
if len(a.array) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return a.array[grand.Intn(len(a.array))], true
|
||||
}
|
||||
|
||||
// Rands randomly returns <size> items from array(no deleting).
|
||||
func (a *SortedStrArray) Rands(size int) []string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
if size > len(a.array) {
|
||||
size = len(a.array)
|
||||
if size <= 0 || len(a.array) == 0 {
|
||||
return nil
|
||||
}
|
||||
n := make([]string, size)
|
||||
for i, v := range grand.Perm(len(a.array)) {
|
||||
n[i] = a.array[v]
|
||||
if i == size-1 {
|
||||
break
|
||||
}
|
||||
array := make([]string, size)
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = a.array[grand.Intn(len(a.array))]
|
||||
}
|
||||
return n
|
||||
return array
|
||||
}
|
||||
|
||||
// Join joins array elements with a string <glue>.
|
||||
|
||||
@ -61,7 +61,7 @@ func Example_basic() {
|
||||
// Output:
|
||||
// 10
|
||||
// [0 1 2 3 4 5 6 7 8 9]
|
||||
// 6
|
||||
// 6 true
|
||||
// true
|
||||
// false
|
||||
// [0 1 2 3 4 5 6 7 8 9 10 11]
|
||||
@ -95,9 +95,9 @@ func Example_popItem() {
|
||||
fmt.Println(array.PopRights(2))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1 true
|
||||
// [2 3]
|
||||
// 9
|
||||
// 9 true
|
||||
// [7 8]
|
||||
}
|
||||
|
||||
|
||||
@ -28,17 +28,38 @@ func Test_Array_Basic(t *testing.T) {
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, 100)
|
||||
t.Assert(array.Get(0), 100)
|
||||
t.Assert(array.Get(1), 1)
|
||||
|
||||
v, ok := array.Get(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Get(1)
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array.Search(100), 0)
|
||||
t.Assert(array3.Search(100), -1)
|
||||
t.Assert(array.Contains(100), true)
|
||||
t.Assert(array.Remove(0), 100)
|
||||
t.Assert(array.Remove(-1), nil)
|
||||
t.Assert(array.Remove(100000), nil)
|
||||
|
||||
t.Assert(array2.Remove(3), 3)
|
||||
t.Assert(array2.Remove(1), 1)
|
||||
v, ok = array.Remove(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Remove(-1)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array.Remove(100000)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array2.Remove(3)
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array2.Remove(1)
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
@ -85,10 +106,23 @@ func TestArray_PushAndPop(t *testing.T) {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.PopLeft(), 0)
|
||||
t.Assert(array.PopRight(), 3)
|
||||
t.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
t.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []interface{}{1, 2})
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []interface{}{1, 2})
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
t.Assert(array.Slice(), []interface{}{1, 2})
|
||||
@ -106,11 +140,19 @@ func TestArray_PopRands(t *testing.T) {
|
||||
func TestArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.New()
|
||||
t.Assert(array.PopLeft(), nil)
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), nil)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), nil)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
|
||||
@ -185,9 +227,15 @@ func TestArray_Fill(t *testing.T) {
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2, true)
|
||||
t.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0, 100, 100})
|
||||
t.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100, 100})
|
||||
t.Assert(array2.Fill(-1, 2, 100).Slice(), []interface{}{100, 100})
|
||||
|
||||
t.Assert(array1.Fill(1, 2, 100), nil)
|
||||
t.Assert(array1.Slice(), []interface{}{0, 100, 100})
|
||||
|
||||
t.Assert(array2.Fill(0, 2, 100), nil)
|
||||
t.Assert(array2.Slice(), []interface{}{100, 100})
|
||||
|
||||
t.AssertNE(array2.Fill(-1, 2, 100), nil)
|
||||
t.Assert(array2.Slice(), []interface{}{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
@ -263,14 +311,15 @@ func TestArray_Rand(t *testing.T) {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
t.Assert(len(array1.Rands(2)), 2)
|
||||
t.Assert(len(array1.Rands(10)), 7)
|
||||
t.Assert(len(array1.Rands(10)), 10)
|
||||
t.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
i1 := a1.Rand()
|
||||
i1, ok := a1.Rand()
|
||||
t.Assert(ok, true)
|
||||
t.Assert(a1.Contains(i1), true)
|
||||
t.Assert(a1.Len(), 4)
|
||||
})
|
||||
|
||||
@ -29,14 +29,31 @@ func Test_IntArray_Basic(t *testing.T) {
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, 100)
|
||||
t.Assert(array.Get(0), 100)
|
||||
t.Assert(array.Get(1), 1)
|
||||
|
||||
v, ok := array.Get(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Get(1)
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array.Search(100), 0)
|
||||
t.Assert(array2.Search(100), -1)
|
||||
t.Assert(array.Contains(100), true)
|
||||
t.Assert(array.Remove(0), 100)
|
||||
t.Assert(array.Remove(-1), 0)
|
||||
t.Assert(array.Remove(100000), 0)
|
||||
|
||||
v, ok = array.Remove(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Remove(-1)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array.Remove(100000)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
t.Assert(array.Len(), 4)
|
||||
@ -81,10 +98,27 @@ func TestIntArray_PushAndPop(t *testing.T) {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.PopLeft(), 0)
|
||||
t.Assert(array.PopRight(), 3)
|
||||
t.AssertIN(array.PopRand(), []int{1, 2})
|
||||
t.AssertIN(array.PopRand(), []int{1, 2})
|
||||
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []int{1, 2})
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []int{1, 2})
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
t.Assert(array.Slice(), []int{1, 2})
|
||||
@ -94,11 +128,23 @@ func TestIntArray_PushAndPop(t *testing.T) {
|
||||
func TestIntArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArray()
|
||||
t.Assert(array.PopLeft(), 0)
|
||||
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), 0)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), 0)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
|
||||
@ -173,9 +219,14 @@ func TestIntArray_Fill(t *testing.T) {
|
||||
a2 := []int{0}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
t.Assert(array1.Fill(1, 2, 100).Slice(), []int{0, 100, 100})
|
||||
t.Assert(array2.Fill(0, 2, 100).Slice(), []int{100, 100})
|
||||
t.Assert(array2.Fill(-1, 2, 100).Slice(), []int{100, 100})
|
||||
t.Assert(array1.Fill(1, 2, 100), nil)
|
||||
t.Assert(array1.Slice(), []int{0, 100, 100})
|
||||
|
||||
t.Assert(array2.Fill(0, 2, 100), nil)
|
||||
t.Assert(array2.Slice(), []int{100, 100})
|
||||
|
||||
t.AssertNE(array2.Fill(-1, 2, 100), nil)
|
||||
t.Assert(array2.Slice(), []int{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
@ -259,9 +310,12 @@ func TestIntArray_Rand(t *testing.T) {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
t.Assert(len(array1.Rands(2)), 2)
|
||||
t.Assert(len(array1.Rands(10)), 7)
|
||||
t.Assert(len(array1.Rands(10)), 10)
|
||||
t.AssertIN(array1.Rands(1)[0], a1)
|
||||
t.AssertIN(array1.Rand(), a1)
|
||||
|
||||
v, ok := array1.Rand()
|
||||
t.AssertIN(v, a1)
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -358,7 +412,9 @@ func TestArray_Get(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
t.Assert(array1.Get(2), 3)
|
||||
v, ok := array1.Get(2)
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 4)
|
||||
})
|
||||
}
|
||||
@ -395,16 +451,19 @@ func TestIntArray_Remove(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 2, 3, 5, 4}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
n1 := array1.Remove(1)
|
||||
t.Assert(n1, 2)
|
||||
v, ok := array1.Remove(1)
|
||||
t.Assert(v, 2)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 4)
|
||||
|
||||
n1 = array1.Remove(0)
|
||||
t.Assert(n1, 1)
|
||||
v, ok = array1.Remove(0)
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 3)
|
||||
|
||||
n1 = array1.Remove(2)
|
||||
t.Assert(n1, 4)
|
||||
v, ok = array1.Remove(2)
|
||||
t.Assert(v, 4)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -29,13 +29,26 @@ func Test_StrArray_Basic(t *testing.T) {
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, "100")
|
||||
t.Assert(array.Get(0), 100)
|
||||
t.Assert(array.Get(1), 1)
|
||||
|
||||
v, ok := array.Get(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array.Search("100"), 0)
|
||||
t.Assert(array.Contains("100"), true)
|
||||
t.Assert(array.Remove(0), 100)
|
||||
t.Assert(array.Remove(-1), "")
|
||||
t.Assert(array.Remove(100000), "")
|
||||
|
||||
v, ok = array.Remove(0)
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Remove(-1)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array.Remove(100000)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Contains("100"), false)
|
||||
array.Append("4")
|
||||
t.Assert(array.Len(), 4)
|
||||
@ -79,10 +92,27 @@ func TestStrArray_PushAndPop(t *testing.T) {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStrArrayFrom(expect)
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.PopLeft(), "0")
|
||||
t.Assert(array.PopRight(), "3")
|
||||
t.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
t.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, "0")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, "3")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []string{"1", "2"})
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.AssertIN(v, []string{"1", "2"})
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Len(), 0)
|
||||
array.PushLeft("1").PushRight("2")
|
||||
t.Assert(array.Slice(), []string{"1", "2"})
|
||||
@ -92,11 +122,19 @@ func TestStrArray_PushAndPop(t *testing.T) {
|
||||
func TestStrArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewStrArray()
|
||||
t.Assert(array.PopLeft(), nil)
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), nil)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), nil)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
|
||||
@ -171,10 +209,12 @@ func TestStrArray_Fill(t *testing.T) {
|
||||
a2 := []string{"0"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
array2 := garray.NewStrArrayFrom(a2)
|
||||
t.Assert(array1.Fill(1, 2, "100").Slice(), []string{"0", "100", "100"})
|
||||
t.Assert(array2.Fill(0, 2, "100").Slice(), []string{"100", "100"})
|
||||
s1 := array2.Fill(-1, 2, "100")
|
||||
t.Assert(s1.Len(), 2)
|
||||
t.Assert(array1.Fill(1, 2, "100"), nil)
|
||||
t.Assert(array1.Slice(), []string{"0", "100", "100"})
|
||||
t.Assert(array2.Fill(0, 2, "100"), nil)
|
||||
t.Assert(array2.Slice(), []string{"100", "100"})
|
||||
t.AssertNE(array2.Fill(-1, 2, "100"), nil)
|
||||
t.Assert(array2.Len(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -250,10 +290,11 @@ func TestStrArray_Rand(t *testing.T) {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
t.Assert(len(array1.Rands(2)), "2")
|
||||
t.Assert(len(array1.Rands(10)), "7")
|
||||
t.Assert(len(array1.Rands(10)), 10)
|
||||
t.AssertIN(array1.Rands(1)[0], a1)
|
||||
t.Assert(len(array1.Rand()), 1)
|
||||
t.AssertIN(array1.Rand(), a1)
|
||||
v, ok := array1.Rand()
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(v, a1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -373,9 +414,10 @@ func TestStrArray_PopRand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
str1 := array1.PopRand()
|
||||
str1, ok := array1.PopRand()
|
||||
t.Assert(strings.Contains("0,1,2,3,4,5,6", str1), true)
|
||||
t.Assert(array1.Len(), 6)
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -405,11 +447,13 @@ func TestStrArray_Remove(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
s1 := array1.Remove(1)
|
||||
s1, ok := array1.Remove(1)
|
||||
t.Assert(s1, "a")
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 4)
|
||||
s1 = array1.Remove(3)
|
||||
s1, ok = array1.Remove(3)
|
||||
t.Assert(s1, "c")
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -99,8 +99,13 @@ func TestSortedArray_Get(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
t.Assert(array1.Get(2), "f")
|
||||
t.Assert(array1.Get(1), "c")
|
||||
v, ok := array1.Get(2)
|
||||
t.Assert(v, "f")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(1)
|
||||
t.Assert(v, "c")
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
|
||||
}
|
||||
@ -112,20 +117,28 @@ func TestSortedArray_Remove(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Remove(1)
|
||||
i1, ok := array1.Remove(1)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(gconv.String(i1), "b")
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1.Contains("b"), false)
|
||||
|
||||
t.Assert(array1.Remove(-1), nil)
|
||||
t.Assert(array1.Remove(100000), nil)
|
||||
v, ok := array1.Remove(-1)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
|
||||
i2 := array1.Remove(0)
|
||||
v, ok = array1.Remove(100000)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
|
||||
i2, ok := array1.Remove(0)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(gconv.String(i2), "a")
|
||||
t.Assert(array1.Len(), 2)
|
||||
t.Assert(array1.Contains("a"), false)
|
||||
|
||||
i3 := array1.Remove(1)
|
||||
i3, ok := array1.Remove(1)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(gconv.String(i3), "d")
|
||||
t.Assert(array1.Len(), 1)
|
||||
t.Assert(array1.Contains("d"), false)
|
||||
@ -140,7 +153,8 @@ func TestSortedArray_PopLeft(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopLeft()
|
||||
i1, ok := array1.PopLeft()
|
||||
t.Assert(ok, true)
|
||||
t.Assert(gconv.String(i1), "a")
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1, []interface{}{"b", "c", "d"})
|
||||
@ -155,7 +169,8 @@ func TestSortedArray_PopRight(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRight()
|
||||
i1, ok := array1.PopRight()
|
||||
t.Assert(ok, true)
|
||||
t.Assert(gconv.String(i1), "d")
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1, []interface{}{"a", "b", "c"})
|
||||
@ -170,7 +185,8 @@ func TestSortedArray_PopRand(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRand()
|
||||
i1, ok := array1.PopRand()
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(i1, []interface{}{"a", "d", "c", "b"})
|
||||
t.Assert(array1.Len(), 3)
|
||||
|
||||
@ -200,11 +216,19 @@ func TestSortedArray_PopRands(t *testing.T) {
|
||||
func TestSortedArray_Empty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArray(gutil.ComparatorInt)
|
||||
t.Assert(array.PopLeft(), nil)
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), nil)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), nil)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
}
|
||||
@ -406,7 +430,8 @@ func TestSortedArray_Rand(t *testing.T) {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Rand()
|
||||
i1, ok := array1.Rand()
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(i1, []interface{}{"a", "d", "c"})
|
||||
t.Assert(array1.Len(), 3)
|
||||
})
|
||||
@ -426,7 +451,7 @@ func TestSortedArray_Rands(t *testing.T) {
|
||||
t.Assert(array1.Len(), 3)
|
||||
|
||||
i1 = array1.Rands(4)
|
||||
t.Assert(len(i1), 3)
|
||||
t.Assert(len(i1), 4)
|
||||
})
|
||||
}
|
||||
|
||||
@ -625,9 +650,22 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.AssertNE(user.Scores, nil)
|
||||
t.Assert(user.Scores.Len(), 3)
|
||||
t.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
t.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
t.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
|
||||
v, ok := user.Scores.PopLeft()
|
||||
t.AssertIN(v, data["Scores"])
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = user.Scores.PopLeft()
|
||||
t.AssertIN(v, data["Scores"])
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = user.Scores.PopLeft()
|
||||
t.AssertIN(v, data["Scores"])
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = user.Scores.PopLeft()
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -68,9 +68,17 @@ func TestSortedIntArray_Get(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
t.Assert(array1.Get(0), 0)
|
||||
t.Assert(array1.Get(1), 1)
|
||||
t.Assert(array1.Get(3), 5)
|
||||
v, ok := array1.Get(0)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(1)
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(3)
|
||||
t.Assert(v, 5)
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -79,26 +87,39 @@ func TestSortedIntArray_Remove(t *testing.T) {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
|
||||
t.Assert(array1.Remove(-1), 0)
|
||||
t.Assert(array1.Remove(100000), 0)
|
||||
v, ok := array1.Remove(-1)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array1.Remove(-100000)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array1.Remove(2)
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
|
||||
i1 := array1.Remove(2)
|
||||
t.Assert(i1, 3)
|
||||
t.Assert(array1.Search(5), 2)
|
||||
|
||||
// 再次删除剩下的数组中的第一个
|
||||
i2 := array1.Remove(0)
|
||||
t.Assert(i2, 0)
|
||||
v, ok = array1.Remove(0)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array1.Search(5), 1)
|
||||
|
||||
a2 := []int{1, 3, 4}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
i3 := array2.Remove(1)
|
||||
|
||||
v, ok = array2.Remove(1)
|
||||
t.Assert(v, 3)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array2.Search(1), 0)
|
||||
t.Assert(i3, 3)
|
||||
i3 = array2.Remove(1)
|
||||
|
||||
v, ok = array2.Remove(1)
|
||||
t.Assert(v, 4)
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array2.Search(4), -1)
|
||||
t.Assert(i3, 4)
|
||||
})
|
||||
}
|
||||
|
||||
@ -106,8 +127,9 @@ func TestSortedIntArray_PopLeft(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopLeft()
|
||||
t.Assert(i1, 1)
|
||||
v, ok := array1.PopLeft()
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1.Search(1), -1)
|
||||
})
|
||||
@ -117,8 +139,9 @@ func TestSortedIntArray_PopRight(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRight()
|
||||
t.Assert(i1, 5)
|
||||
v, ok := array1.PopRight()
|
||||
t.Assert(v, 5)
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1.Search(5), -1)
|
||||
})
|
||||
@ -128,7 +151,8 @@ func TestSortedIntArray_PopRand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRand()
|
||||
i1, ok := array1.PopRand()
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1.Search(i1), -1)
|
||||
t.AssertIN(i1, []int{1, 3, 5, 2})
|
||||
@ -155,11 +179,19 @@ func TestSortedIntArray_PopRands(t *testing.T) {
|
||||
func TestSortedIntArray_Empty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedIntArray()
|
||||
t.Assert(array.PopLeft(), 0)
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), 0)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), 0)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
}
|
||||
@ -340,8 +372,9 @@ func TestSortedIntArray_Rand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rand() //按每几个元素切成一个数组
|
||||
ns1, ok := array1.Rand()
|
||||
t.AssertIN(ns1, a1)
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -349,13 +382,12 @@ func TestSortedIntArray_Rands(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rands(2) //按每几个元素切成一个数组
|
||||
ns1 := array1.Rands(2)
|
||||
t.AssertIN(ns1, a1)
|
||||
t.Assert(len(ns1), 2)
|
||||
|
||||
ns2 := array1.Rands(6) //按每几个元素切成一个数组
|
||||
t.AssertIN(ns2, a1)
|
||||
t.Assert(len(ns2), 5)
|
||||
ns2 := array1.Rands(6)
|
||||
t.Assert(len(ns2), 6)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -68,8 +68,13 @@ func TestSortedStrArray_Get(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
t.Assert(array1.Get(2), "c")
|
||||
t.Assert(array1.Get(0), "a")
|
||||
v, ok := array1.Get(2)
|
||||
t.Assert(v, "c")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(0)
|
||||
t.Assert(v, "a")
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -78,20 +83,36 @@ func TestSortedStrArray_Remove(t *testing.T) {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
|
||||
t.Assert(array1.Remove(-1), "")
|
||||
t.Assert(array1.Remove(100000), "")
|
||||
v, ok := array1.Remove(-1)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array1.Remove(100000)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
v, ok = array1.Remove(2)
|
||||
t.Assert(v, "c")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(2)
|
||||
t.Assert(v, "d")
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array1.Remove(2), "c")
|
||||
t.Assert(array1.Get(2), "d")
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1.Contains("c"), false)
|
||||
|
||||
t.Assert(array1.Remove(0), "a")
|
||||
v, ok = array1.Remove(0)
|
||||
t.Assert(v, "a")
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array1.Len(), 2)
|
||||
t.Assert(array1.Contains("a"), false)
|
||||
|
||||
// 此时array1里的元素只剩下2个
|
||||
t.Assert(array1.Remove(1), "d")
|
||||
v, ok = array1.Remove(1)
|
||||
t.Assert(v, "d")
|
||||
t.Assert(ok, true)
|
||||
|
||||
t.Assert(array1.Len(), 1)
|
||||
})
|
||||
}
|
||||
@ -100,8 +121,9 @@ func TestSortedStrArray_PopLeft(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopLeft()
|
||||
t.Assert(s1, "a")
|
||||
v, ok := array1.PopLeft()
|
||||
t.Assert(v, "a")
|
||||
t.Assert(ok, true)
|
||||
t.Assert(array1.Len(), 4)
|
||||
t.Assert(array1.Contains("a"), false)
|
||||
})
|
||||
@ -111,8 +133,9 @@ func TestSortedStrArray_PopRight(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRight()
|
||||
t.Assert(s1, "e")
|
||||
v, ok := array1.PopRight()
|
||||
t.Assert(v, "e")
|
||||
t.Assert(ok, ok)
|
||||
t.Assert(array1.Len(), 4)
|
||||
t.Assert(array1.Contains("e"), false)
|
||||
})
|
||||
@ -122,7 +145,8 @@ func TestSortedStrArray_PopRand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRand()
|
||||
s1, ok := array1.PopRand()
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
t.Assert(array1.Len(), 4)
|
||||
t.Assert(array1.Contains(s1), false)
|
||||
@ -147,11 +171,19 @@ func TestSortedStrArray_PopRands(t *testing.T) {
|
||||
func TestSortedStrArray_Empty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedStrArray()
|
||||
t.Assert(array.PopLeft(), nil)
|
||||
v, ok := array.PopLeft()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopLefts(10), nil)
|
||||
t.Assert(array.PopRight(), nil)
|
||||
|
||||
v, ok = array.PopRight()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRights(10), nil)
|
||||
t.Assert(array.PopRand(), nil)
|
||||
|
||||
v, ok = array.PopRand()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
t.Assert(array.PopRands(10), nil)
|
||||
})
|
||||
}
|
||||
@ -283,7 +315,9 @@ func TestSortedStrArray_Rand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
t.AssertIN(array1.Rand(), []string{"e", "a", "d"})
|
||||
v, ok := array1.Rand()
|
||||
t.AssertIN(v, []string{"e", "a", "d"})
|
||||
t.Assert(ok, true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -297,8 +331,7 @@ func TestSortedStrArray_Rands(t *testing.T) {
|
||||
t.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.Rands(4)
|
||||
t.AssertIN(s1, []string{"e", "a", "d"})
|
||||
t.Assert(len(s1), 3)
|
||||
t.Assert(len(s1), 4)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -8,9 +8,11 @@ package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/container/gset"
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"time"
|
||||
)
|
||||
|
||||
// getModel creates and returns a cloned model of current model if <safe> is true, or else it returns
|
||||
@ -45,9 +47,25 @@ func (m *Model) doFilterDataMapForInsertOrUpdate(data Map, allowOmitEmpty bool)
|
||||
}
|
||||
// Remove key-value pairs of which the value is empty.
|
||||
if allowOmitEmpty && m.option&OPTION_OMITEMPTY > 0 {
|
||||
m := gmap.NewStrAnyMapFrom(data)
|
||||
m.FilterEmpty()
|
||||
data = m.Map()
|
||||
tempMap := make(Map, len(data))
|
||||
for k, v := range data {
|
||||
if empty.IsEmpty(v) {
|
||||
continue
|
||||
}
|
||||
// Special type filtering.
|
||||
switch r := v.(type) {
|
||||
case time.Time:
|
||||
if r.IsZero() {
|
||||
continue
|
||||
}
|
||||
case gtime.Time:
|
||||
if r.IsZero() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
tempMap[k] = v
|
||||
}
|
||||
data = tempMap
|
||||
}
|
||||
|
||||
if len(m.fields) > 0 && m.fields != "*" {
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
|
||||
@ -2098,3 +2099,27 @@ func Test_Model_FieldsExStruct(t *testing.T) {
|
||||
t.Assert(n, 10)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_OmitEmpty_Time(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int `orm:"id" json:"id"`
|
||||
Passport string `orm:"password" json:"pass_port"`
|
||||
Password string `orm:"password" json:"password"`
|
||||
Time time.Time `orm:"create_time" `
|
||||
}
|
||||
user := &User{
|
||||
Id: 1,
|
||||
Passport: "111",
|
||||
Password: "222",
|
||||
Time: time.Time{},
|
||||
}
|
||||
r, err := db.Table(table).OmitEmpty().Data(user).WherePri(1).Update()
|
||||
t.Assert(err, nil)
|
||||
n, err := r.RowsAffected()
|
||||
t.Assert(err, nil)
|
||||
t.Assert(n, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ package ghttp
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
@ -94,7 +94,7 @@ func (c *Client) SetContentType(contentType string) *Client {
|
||||
|
||||
// SetHeaderRaw sets custom HTTP header using raw string.
|
||||
func (c *Client) SetHeaderRaw(headers string) *Client {
|
||||
for _, line := range strings.Split(strings.TrimSpace(headers), "\n") {
|
||||
for _, line := range gstr.SplitAndTrim(headers, "\n") {
|
||||
array, _ := gregex.MatchString(`^([\w\-]+):\s*(.+)`, line)
|
||||
if len(array) >= 3 {
|
||||
c.header[array[1]] = array[2]
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Client_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/hello", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
@ -42,8 +42,32 @@ func Test_Client_Basic(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Client_BasicAuth(t *testing.T) {
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/auth", func(r *ghttp.Request) {
|
||||
if r.BasicAuth("admin", "admin") {
|
||||
r.Response.Write("1")
|
||||
} else {
|
||||
r.Response.Write("0")
|
||||
}
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
t.Assert(c.BasicAuth("admin", "123").GetContent("/auth"), "0")
|
||||
t.Assert(c.BasicAuth("admin", "admin").GetContent("/auth"), "1")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Client_Cookie(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/cookie", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Cookie.Get("test"))
|
||||
@ -64,7 +88,7 @@ func Test_Client_Cookie(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Cookies(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/cookie", func(r *ghttp.Request) {
|
||||
r.Cookie.Set("test1", "1")
|
||||
@ -97,7 +121,7 @@ func Test_Client_Cookies(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Chain_Header(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/header1", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Header.Get("test1"))
|
||||
@ -122,7 +146,7 @@ func Test_Client_Chain_Header(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Chain_Context(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/context", func(r *ghttp.Request) {
|
||||
time.Sleep(1 * time.Second)
|
||||
@ -147,7 +171,7 @@ func Test_Client_Chain_Context(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Chain_Timeout(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/timeout", func(r *ghttp.Request) {
|
||||
time.Sleep(1 * time.Second)
|
||||
@ -168,7 +192,7 @@ func Test_Client_Chain_Timeout(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Chain_ContentJson(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/json", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("name"), r.Get("score"))
|
||||
@ -197,7 +221,7 @@ func Test_Client_Chain_ContentJson(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Client_Chain_ContentXml(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/xml", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("name"), r.Get("score"))
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Context(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Cookie(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Cookie.Set(r.GetString("k"), r.GetString("v"))
|
||||
|
||||
@ -24,7 +24,7 @@ import (
|
||||
func Test_Log(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
logDir := gfile.TempDir(gtime.TimestampNanoStr())
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/hello", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_GetUrl(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/url", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetUrl())
|
||||
|
||||
@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_BindMiddleware_Basic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -60,7 +60,7 @@ func Test_BindMiddleware_Basic1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddleware_Basic2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -87,7 +87,7 @@ func Test_BindMiddleware_Basic2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddleware_Basic3(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -131,7 +131,7 @@ func Test_BindMiddleware_Basic3(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddleware_Basic4(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
@ -163,7 +163,7 @@ func Test_BindMiddleware_Basic4(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Middleware_With_Static(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
@ -193,7 +193,7 @@ func Test_Middleware_With_Static(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Middleware_Status(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
@ -224,7 +224,7 @@ func Test_Middleware_Status(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Middleware_Hook_With_Static(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
a := garray.New(true)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
@ -278,7 +278,7 @@ func Test_Middleware_Hook_With_Static(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddleware_Status(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -304,7 +304,7 @@ func Test_BindMiddleware_Status(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -335,7 +335,7 @@ func Test_BindMiddlewareDefault_Basic1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("PUT:/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -368,7 +368,7 @@ func Test_BindMiddlewareDefault_Basic2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic3(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -397,7 +397,7 @@ func Test_BindMiddlewareDefault_Basic3(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic4(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -426,7 +426,7 @@ func Test_BindMiddlewareDefault_Basic4(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic5(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -455,7 +455,7 @@ func Test_BindMiddlewareDefault_Basic5(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Status(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -501,7 +501,7 @@ func (o *ObjectMiddleware) Info(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_BindMiddlewareDefault_Basic6(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObject("/", new(ObjectMiddleware))
|
||||
s.BindMiddlewareDefault(func(r *ghttp.Request) {
|
||||
@ -534,7 +534,7 @@ func Test_BindMiddlewareDefault_Basic6(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Hook_Middleware_Basic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
@ -591,7 +591,7 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Middleware_CORSAndAuth(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Use(MiddlewareCORS)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
@ -645,7 +645,7 @@ func MiddlewareScope3(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Middleware_Scope(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareScope1)
|
||||
@ -682,7 +682,7 @@ func Test_Middleware_Scope(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Middleware_Panic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
i := 0
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
|
||||
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Middleware_CORS1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
@ -79,7 +79,7 @@ func Test_Middleware_CORS1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Middleware_CORS2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareCORS)
|
||||
|
||||
@ -22,7 +22,7 @@ import (
|
||||
|
||||
func Test_Params_File_Single(t *testing.T) {
|
||||
dstDirPath := gfile.TempDir(gtime.TimestampNanoStr())
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/upload/single", func(r *ghttp.Request) {
|
||||
file := r.GetUploadFile("file")
|
||||
@ -76,7 +76,7 @@ func Test_Params_File_Single(t *testing.T) {
|
||||
|
||||
func Test_Params_File_CustomName(t *testing.T) {
|
||||
dstDirPath := gfile.TempDir(gtime.TimestampNanoStr())
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/upload/single", func(r *ghttp.Request) {
|
||||
file := r.GetUploadFile("file")
|
||||
@ -113,7 +113,7 @@ func Test_Params_File_CustomName(t *testing.T) {
|
||||
|
||||
func Test_Params_File_Batch(t *testing.T) {
|
||||
dstDirPath := gfile.TempDir(gtime.TimestampNanoStr())
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/upload/batch", func(r *ghttp.Request) {
|
||||
files := r.GetUploadFiles("file")
|
||||
|
||||
@ -25,7 +25,7 @@ func Test_Params_Json_Request(t *testing.T) {
|
||||
Pass1 string `p:"password1"`
|
||||
Pass2 string `p:"password2" v:"required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致"`
|
||||
}
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteExit(r.Get("id"), r.Get("name"))
|
||||
@ -71,7 +71,7 @@ func Test_Params_Json_Response(t *testing.T) {
|
||||
Pass2 string `json:"password2"`
|
||||
}
|
||||
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/json1", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(User{
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Params_Page(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/list", func(r *ghttp.Request) {
|
||||
|
||||
@ -26,7 +26,7 @@ func Test_Params_Struct(t *testing.T) {
|
||||
Pass1 string `p:"password1"`
|
||||
Pass2 string `p:"password2" v:"passwd1 @required|length:2,20|password3#||密码强度不足"`
|
||||
}
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/struct1", func(r *ghttp.Request) {
|
||||
if m := r.GetMap(); len(m) > 0 {
|
||||
|
||||
@ -23,7 +23,7 @@ func Test_Params_Basic(t *testing.T) {
|
||||
Pass1 string `params:"password1"`
|
||||
Pass2 string `params:"password2"`
|
||||
}
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
// GET
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
@ -405,7 +405,7 @@ func Test_Params_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Params_SupportChars(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/form-value", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetQuery("test-value"))
|
||||
@ -430,7 +430,7 @@ func Test_Params_SupportChars(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Params_Priority(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/query", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetQuery("a"))
|
||||
|
||||
@ -24,7 +24,7 @@ func Test_Params_Xml_Request(t *testing.T) {
|
||||
Pass1 string `p:"password1"`
|
||||
Pass2 string `p:"password2" v:"required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致"`
|
||||
}
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteExit(r.Get("id"), r.Get("name"))
|
||||
|
||||
@ -20,7 +20,7 @@ import (
|
||||
|
||||
func TestServer_EnablePProf(t *testing.T) {
|
||||
C(t, func(t *T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.EnablePProf("/pprof")
|
||||
s.SetDumpRouterMap(false)
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/:name", func(r *ghttp.Request) {
|
||||
r.Response.Write("/:name")
|
||||
@ -52,7 +52,7 @@ func Test_Router_Basic(t *testing.T) {
|
||||
|
||||
// HTTP method register.
|
||||
func Test_Router_Method(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("GET:/get", func(r *ghttp.Request) {
|
||||
|
||||
@ -94,7 +94,7 @@ func Test_Router_Method(t *testing.T) {
|
||||
|
||||
// Extra char '/' of the router.
|
||||
func Test_Router_ExtraChar(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/api", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/test", func(r *ghttp.Request) {
|
||||
@ -119,7 +119,7 @@ func Test_Router_ExtraChar(t *testing.T) {
|
||||
|
||||
// Custom status handler.
|
||||
func Test_Router_Status(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/200", func(r *ghttp.Request) {
|
||||
r.Response.WriteStatus(200)
|
||||
@ -171,7 +171,7 @@ func Test_Router_Status(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_CustomStatusHandler(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
@ -200,7 +200,7 @@ func Test_Router_CustomStatusHandler(t *testing.T) {
|
||||
|
||||
// 404 not found router.
|
||||
func Test_Router_404(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
@ -224,7 +224,7 @@ func Test_Router_404(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Priority(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/admin", func(r *ghttp.Request) {
|
||||
r.Response.Write("admin")
|
||||
|
||||
@ -52,7 +52,7 @@ func (c *ControllerRest) Head() {
|
||||
|
||||
// 控制器注册测试
|
||||
func Test_Router_ControllerRest(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindControllerRest("/", new(ControllerRest))
|
||||
s.BindControllerRest("/{.struct}/{.method}", new(ControllerRest))
|
||||
|
||||
@ -44,7 +44,7 @@ func (c *Controller) Info() {
|
||||
}
|
||||
|
||||
func Test_Router_Controller1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindController("/", new(Controller))
|
||||
s.BindController("/{.struct}/{.method}", new(Controller))
|
||||
@ -75,7 +75,7 @@ func Test_Router_Controller1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Controller2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindController("/controller", new(Controller), "Show, Info")
|
||||
s.SetPort(p)
|
||||
@ -101,7 +101,7 @@ func Test_Router_Controller2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_ControllerMethod(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindControllerMethod("/controller-info", new(Controller), "Info")
|
||||
s.SetPort(p)
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_DomainBasic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindHandler("/:name", func(r *ghttp.Request) {
|
||||
@ -69,7 +69,7 @@ func Test_Router_DomainBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainMethod(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindHandler("GET:/get", func(r *ghttp.Request) {
|
||||
@ -161,7 +161,7 @@ func Test_Router_DomainMethod(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainStatus(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindHandler("/200", func(r *ghttp.Request) {
|
||||
@ -257,7 +257,7 @@ func Test_Router_DomainStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainCustomStatusHandler(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindHandler("/", func(r *ghttp.Request) {
|
||||
@ -296,7 +296,7 @@ func Test_Router_DomainCustomStatusHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Domain404(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindHandler("/", func(r *ghttp.Request) {
|
||||
@ -329,7 +329,7 @@ func Test_Router_Domain404(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainGroup(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.Group("/", func(group *ghttp.RouterGroup) {
|
||||
|
||||
@ -60,7 +60,7 @@ func (c *DomainControllerRest) Head() {
|
||||
|
||||
// 控制器注册测试
|
||||
func Test_Router_DomainControllerRest(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindControllerRest("/", new(DomainControllerRest))
|
||||
|
||||
@ -43,7 +43,7 @@ func (c *DomainController) Info() {
|
||||
}
|
||||
|
||||
func Test_Router_DomainController1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindController("/", new(DomainController))
|
||||
s.SetPort(p)
|
||||
@ -93,7 +93,7 @@ func Test_Router_DomainController1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainController2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindController("/controller", new(DomainController), "Show, Info")
|
||||
s.SetPort(p)
|
||||
@ -146,7 +146,7 @@ func Test_Router_DomainController2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainControllerMethod(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindControllerMethod("/controller-info", new(DomainController), "Info")
|
||||
s.SetPort(p)
|
||||
|
||||
@ -55,7 +55,7 @@ func (o *DomainObjectRest) Head(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainObjectRest(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
d := s.Domain("localhost, local")
|
||||
d.BindObjectRest("/", new(DomainObjectRest))
|
||||
|
||||
@ -39,7 +39,7 @@ func (o *DomainObject) Info(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainObject1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindObject("/", new(DomainObject))
|
||||
s.SetPort(p)
|
||||
@ -88,7 +88,7 @@ func Test_Router_DomainObject1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainObject2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindObject("/object", new(DomainObject), "Show, Info")
|
||||
s.SetPort(p)
|
||||
@ -139,7 +139,7 @@ func Test_Router_DomainObject2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_DomainObjectMethod(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Domain("localhost, local").BindObjectMethod("/object-info", new(DomainObject), "Info")
|
||||
s.SetPort(p)
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_Exit(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHookHandlerByMap("/*", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) { r.Response.Write("1") },
|
||||
@ -46,7 +46,7 @@ func Test_Router_Exit(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_ExitHook(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/priority/show", func(r *ghttp.Request) {
|
||||
r.Response.Write("show")
|
||||
@ -84,7 +84,7 @@ func Test_Router_ExitHook(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_ExitAll(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/priority/show", func(r *ghttp.Request) {
|
||||
r.Response.Write("show")
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_Group_Group(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_Group_Hook1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
group := s.Group("/api")
|
||||
group.GET("/handler", func(r *ghttp.Request) {
|
||||
@ -46,7 +46,7 @@ func Test_Router_Group_Hook1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Group_Hook2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
g := s.Group("/api")
|
||||
g.GET("/handler", func(r *ghttp.Request) {
|
||||
@ -76,7 +76,7 @@ func Test_Router_Group_Hook2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Group_Hook3(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.Group("/api").Bind([]g.Slice{
|
||||
{"ALL", "handler", func(r *ghttp.Request) {
|
||||
|
||||
@ -98,7 +98,7 @@ func (o *GroupObjRest) Head(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_GroupRest(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
g := s.Group("/api")
|
||||
ctl := new(GroupCtlRest)
|
||||
|
||||
@ -71,7 +71,7 @@ func Handler(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_GroupBasic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
obj := new(GroupObject)
|
||||
ctl := new(GroupController)
|
||||
@ -118,7 +118,7 @@ func Test_Router_GroupBasic1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_GroupBasic2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
obj := new(GroupObject)
|
||||
ctl := new(GroupController)
|
||||
@ -160,7 +160,7 @@ func Test_Router_GroupBasic2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_GroupBuildInVar(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
obj := new(GroupObject)
|
||||
ctl := new(GroupController)
|
||||
@ -192,7 +192,7 @@ func Test_Router_GroupBuildInVar(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Group_Mthods(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
obj := new(GroupObject)
|
||||
ctl := new(GroupController)
|
||||
@ -216,8 +216,8 @@ func Test_Router_Group_Mthods(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Group_MultiServer(t *testing.T) {
|
||||
p1 := ports.PopRand()
|
||||
p2 := ports.PopRand()
|
||||
p1, _ := ports.PopRand()
|
||||
p2, _ := ports.PopRand()
|
||||
s1 := g.Server(p1)
|
||||
s2 := g.Server(p2)
|
||||
s1.Group("/", func(group *ghttp.RouterGroup) {
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Router_Hook_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHookHandlerByMap("/*", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) { r.Response.Write("1") },
|
||||
@ -44,7 +44,7 @@ func Test_Router_Hook_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Hook_Fuzzy_Router(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
i := 1000
|
||||
pattern1 := "/:name/info"
|
||||
@ -88,7 +88,7 @@ func Test_Router_Hook_Fuzzy_Router(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Hook_Priority(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/priority/show", func(r *ghttp.Request) {
|
||||
r.Response.Write("show")
|
||||
@ -127,7 +127,7 @@ func Test_Router_Hook_Priority(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Hook_Multi(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/multi-hook", func(r *ghttp.Request) {
|
||||
r.Response.Write("show")
|
||||
|
||||
@ -23,7 +23,7 @@ func (o *NamesObject) ShowName(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_NameToUri_FullName(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
|
||||
s.BindObject("/{.struct}/{.method}", new(NamesObject))
|
||||
@ -44,7 +44,7 @@ func Test_NameToUri_FullName(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_NameToUri_AllLower(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
|
||||
s.BindObject("/{.struct}/{.method}", new(NamesObject))
|
||||
@ -65,7 +65,7 @@ func Test_NameToUri_AllLower(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_NameToUri_Camel(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_CAMEL)
|
||||
s.BindObject("/{.struct}/{.method}", new(NamesObject))
|
||||
@ -86,7 +86,7 @@ func Test_NameToUri_Camel(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_NameToUri_Default(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_DEFAULT)
|
||||
s.BindObject("/{.struct}/{.method}", new(NamesObject))
|
||||
|
||||
@ -55,7 +55,7 @@ func (o *ObjectRest) Head(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_ObjectRest(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObjectRest("/", new(ObjectRest))
|
||||
s.BindObjectRest("/{.struct}/{.method}", new(ObjectRest))
|
||||
|
||||
@ -43,7 +43,7 @@ func (o *ObjectRest2) Delete(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_ObjectRest_Id(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObjectRest("/object/:id", new(ObjectRest2))
|
||||
s.SetPort(p)
|
||||
|
||||
@ -39,7 +39,7 @@ func (o *Object) Info(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Test_Router_Object1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObject("/", new(Object))
|
||||
s.BindObject("/{.struct}/{.method}", new(Object))
|
||||
@ -70,7 +70,7 @@ func Test_Router_Object1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_Object2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObject("/object", new(Object), "Show, Info")
|
||||
s.SetPort(p)
|
||||
@ -96,7 +96,7 @@ func Test_Router_Object2(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Router_ObjectMethod(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindObjectMethod("/object-info", new(Object), "Info")
|
||||
s.SetPort(p)
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Session_Cookie(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set(r.GetString("k"), r.GetString("v"))
|
||||
@ -64,7 +64,7 @@ func Test_Session_Cookie(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Session_Header(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set(r.GetString("k"), r.GetString("v"))
|
||||
@ -115,7 +115,7 @@ func Test_Session_Header(t *testing.T) {
|
||||
|
||||
func Test_Session_StorageFile(t *testing.T) {
|
||||
sessionId := ""
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set(r.GetString("k"), r.GetString("v"))
|
||||
|
||||
@ -25,7 +25,7 @@ import (
|
||||
func Test_Static_ServerRoot(t *testing.T) {
|
||||
// SetServerRoot with absolute path
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
@ -44,7 +44,7 @@ func Test_Static_ServerRoot(t *testing.T) {
|
||||
|
||||
// SetServerRoot with relative path
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`static/test/%d`, p)
|
||||
defer gfile.Remove(path)
|
||||
@ -64,7 +64,7 @@ func Test_Static_ServerRoot(t *testing.T) {
|
||||
|
||||
func Test_Static_ServerRoot_Security(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetServerRoot(gdebug.TestDataPath("static1"))
|
||||
s.SetPort(p)
|
||||
@ -85,7 +85,7 @@ func Test_Static_ServerRoot_Security(t *testing.T) {
|
||||
|
||||
func Test_Static_Folder_Forbidden(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
@ -106,7 +106,7 @@ func Test_Static_Folder_Forbidden(t *testing.T) {
|
||||
|
||||
func Test_Static_IndexFolder(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
@ -129,7 +129,7 @@ func Test_Static_IndexFolder(t *testing.T) {
|
||||
|
||||
func Test_Static_IndexFiles1(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
@ -151,7 +151,7 @@ func Test_Static_IndexFiles1(t *testing.T) {
|
||||
|
||||
func Test_Static_IndexFiles2(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
@ -173,7 +173,7 @@ func Test_Static_IndexFiles2(t *testing.T) {
|
||||
|
||||
func Test_Static_AddSearchPath1(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
path2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.TempDir(), p, p)
|
||||
@ -196,7 +196,7 @@ func Test_Static_AddSearchPath1(t *testing.T) {
|
||||
|
||||
func Test_Static_AddSearchPath2(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
path2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.TempDir(), p, p)
|
||||
@ -220,7 +220,7 @@ func Test_Static_AddSearchPath2(t *testing.T) {
|
||||
|
||||
func Test_Static_AddStaticPath(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
path2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.TempDir(), p, p)
|
||||
@ -245,7 +245,7 @@ func Test_Static_AddStaticPath(t *testing.T) {
|
||||
|
||||
func Test_Static_AddStaticPath_Priority(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path1 := fmt.Sprintf(`%s/ghttp/static/test/%d/test`, gfile.TempDir(), p)
|
||||
path2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d/test`, gfile.TempDir(), p, p)
|
||||
@ -270,7 +270,7 @@ func Test_Static_AddStaticPath_Priority(t *testing.T) {
|
||||
|
||||
func Test_Static_Rewrite(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
path := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.TempDir(), p)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
@ -24,7 +24,7 @@ import (
|
||||
func Test_Template_Basic(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v := gview.New(gdebug.TestDataPath("template", "basic"))
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetView(v)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
@ -50,7 +50,7 @@ func Test_Template_Encode(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v := gview.New(gdebug.TestDataPath("template", "basic"))
|
||||
v.SetAutoEncode(true)
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetView(v)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
@ -75,7 +75,7 @@ func Test_Template_Encode(t *testing.T) {
|
||||
func Test_Template_Layout1(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v := gview.New(gdebug.TestDataPath("template", "layout1"))
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetView(v)
|
||||
s.BindHandler("/layout", func(r *ghttp.Request) {
|
||||
@ -105,7 +105,7 @@ func Test_Template_Layout1(t *testing.T) {
|
||||
func Test_Template_Layout2(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v := gview.New(gdebug.TestDataPath("template", "layout2"))
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetView(v)
|
||||
s.BindHandler("/main1", func(r *ghttp.Request) {
|
||||
@ -144,7 +144,7 @@ func Test_Template_XSS(t *testing.T) {
|
||||
v := gview.New()
|
||||
v.SetAutoEncode(true)
|
||||
c := "<br>"
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.SetView(v)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
|
||||
@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_WebSocket(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/ws", func(r *ghttp.Request) {
|
||||
ws, err := r.WebSocket()
|
||||
|
||||
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Package_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -96,7 +96,7 @@ func Test_Package_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Package_Timeout(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -132,7 +132,7 @@ func Test_Package_Timeout(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Package_Option(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
option := gtcp.PkgOption{HeaderSize: 1}
|
||||
|
||||
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Pool_Package_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -96,7 +96,7 @@ func Test_Pool_Package_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Pool_Package_Timeout(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -132,7 +132,7 @@ func Test_Pool_Package_Timeout(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Pool_Package_Option(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
option := gtcp.PkgOption{HeaderSize: 1}
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Pool_Basic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -42,7 +42,7 @@ func Test_Pool_Basic1(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Pool_Basic2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
conn.Close()
|
||||
})
|
||||
|
||||
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gudp.NewServer(fmt.Sprintf("127.0.0.1:%d", p), func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
@ -75,7 +75,7 @@ func Test_Basic(t *testing.T) {
|
||||
// If the read buffer size is less than the sent package size,
|
||||
// the rest data would be dropped.
|
||||
func Test_Buffer(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
p, _ := ports.PopRand()
|
||||
s := gudp.NewServer(fmt.Sprintf("127.0.0.1:%d", p), func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
|
||||
@ -187,9 +187,9 @@ func (l *Logger) rotateChecksTimely() {
|
||||
for _, array := range backupFilesMap {
|
||||
diff := array.Len() - l.config.RotateBackupLimit
|
||||
for i := 0; i < diff; i++ {
|
||||
path := array.PopLeft().(string)
|
||||
path, _ := array.PopLeft()
|
||||
intlog.Printf(`remove exceeded backup limit file: %s`, path)
|
||||
if err := gfile.Remove(path); err != nil {
|
||||
if err := gfile.Remove(path.(string)); err != nil {
|
||||
intlog.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package gmutex_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -239,35 +240,40 @@ func Test_Mutex_RLockFunc(t *testing.T) {
|
||||
|
||||
func Test_Mutex_TryRLockFunc(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
mu := gmutex.New()
|
||||
array := garray.New(true)
|
||||
var (
|
||||
mu = gmutex.New()
|
||||
array = garray.New(true)
|
||||
)
|
||||
// First writing lock
|
||||
go func() {
|
||||
mu.LockFunc(func() {
|
||||
array.Append(1)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
glog.Println("lock1 done")
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
})
|
||||
}()
|
||||
// This goroutine never gets the lock.
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
mu.TryRLockFunc(func() {
|
||||
array.Append(1)
|
||||
})
|
||||
}()
|
||||
for index := 0; index < 1000; index++ {
|
||||
go func() {
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
time.Sleep(4000 * time.Millisecond)
|
||||
mu.TryRLockFunc(func() {
|
||||
array.Append(1)
|
||||
})
|
||||
}()
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
t.Assert(array.Len(), 1)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
t.Assert(array.Len(), 1)
|
||||
time.Sleep(600 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
t.Assert(array.Len(), 1)
|
||||
time.Sleep(600 * time.Millisecond)
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
t.Assert(array.Len(), 1001)
|
||||
})
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ func New(path string, cache bool) *SPath {
|
||||
}
|
||||
if len(path) > 0 {
|
||||
if _, err := sp.Add(path); err != nil {
|
||||
intlog.Print(err)
|
||||
//intlog.Print(err)
|
||||
}
|
||||
}
|
||||
return sp
|
||||
|
||||
@ -11,7 +11,8 @@
|
||||
// between gtimer and gcron are as follows:
|
||||
// 1. package gcron is implemented based on package gtimer.
|
||||
// 2. gtimer is designed for high performance and for millions of timing jobs.
|
||||
// 3. gcron supports configuration pattern grammar like linux crontab, which is more manually readable.
|
||||
// 3. gcron supports configuration pattern grammar like linux crontab, which is more manually
|
||||
// readable.
|
||||
// 4. gtimer's benchmark OP is measured in nanoseconds, and gcron's benchmark OP is measured
|
||||
// in microseconds.
|
||||
//
|
||||
|
||||
@ -105,6 +105,7 @@ func Symbols(n int) string {
|
||||
}
|
||||
|
||||
// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).
|
||||
// TODO performance improving for large slice producing.
|
||||
func Perm(n int) []int {
|
||||
m := make([]int, n)
|
||||
for i := 0; i < n; i++ {
|
||||
|
||||
@ -18,13 +18,31 @@ import (
|
||||
|
||||
var buffer = make([]byte, 8)
|
||||
|
||||
func Benchmark_Rand1(b *testing.B) {
|
||||
func Benchmark_Rand_Intn(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
grand.N(0, 99)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Rand2(b *testing.B) {
|
||||
func Benchmark_Perm10(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
grand.Perm(10)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Perm100(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
grand.Perm(100)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Rand_N1(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
grand.N(0, 99)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Rand_N2(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
grand.N(0, 999999999)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.11.7"
|
||||
const VERSION = "v1.12.1"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user