mirror of
https://gitee.com/johng/gf
synced 2026-06-09 11:03:59 +08:00
Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c02f502bd8 | |||
| d5d6b8c303 | |||
| fe152dfa63 | |||
| 1b4a879eda | |||
| c5aa493d24 | |||
| a88363e34c | |||
| 0f1261d0e3 | |||
| c41d11df9f | |||
| 1e680c7a8b | |||
| e981143ead | |||
| 4de6881c89 | |||
| 46c42ec249 | |||
| d068c1418e | |||
| 41db3a32f4 | |||
| b3a00becf3 | |||
| d1d8cd8482 | |||
| 1228907d59 | |||
| 57b54414d6 | |||
| 548a0c47af | |||
| 4934564b7b | |||
| 7348d14fef | |||
| 9cddb7ed9a | |||
| 8c84de3f73 | |||
| 96529a4c1c | |||
| c7a729fe06 | |||
| 23d404f681 | |||
| 887aeee2d4 | |||
| 622dbfda31 | |||
| 80cf3e833b | |||
| d305d25935 | |||
| 81502cfb6d | |||
| 5950a3fcc3 | |||
| 55f5e6d7aa | |||
| e2070e785c | |||
| 905d5abed6 | |||
| 211e06d04d | |||
| 7aaf9e9228 | |||
| a901e7177c | |||
| afc2bcfb28 | |||
| 8da204fbd8 | |||
| 5aa3212fe1 | |||
| 17d49510c4 | |||
| 4af8ae1470 | |||
| 3a5c660693 | |||
| 9e65100a06 | |||
| 399e47c548 | |||
| abdf8e696c | |||
| 4a2e217625 | |||
| 52d0280137 | |||
| 5be9765eb7 | |||
| cdb9488752 | |||
| 0388113870 | |||
| c6dfb4d4f8 | |||
| 4a40b58b63 | |||
| 407068a0bf | |||
| 165330ec68 | |||
| 6e7d08fbfb | |||
| 1ae77f56e5 | |||
| fccac04980 | |||
| 469f9c7ce5 | |||
| d6d37248f6 | |||
| cb1084b770 | |||
| e6d4459992 | |||
| 1afb5a4bc5 | |||
| c124f172b2 | |||
| dbd4a7c1d4 | |||
| a4d30ef206 | |||
| 0a616173ef | |||
| 597f210f85 | |||
| 24bd83feb0 | |||
| 3855786905 | |||
| 1f670a1ab2 | |||
| d97fda794c | |||
| c034d25299 | |||
| dd6152fe8a | |||
| 485fe572ff | |||
| 15bf5d9a4d | |||
| 08aa7c4e4c | |||
| 442c658be0 | |||
| 5aa8ce1c6b | |||
| ad8ece68c6 | |||
| 74525ba8f7 | |||
| 46d46afaaf | |||
| 13eb1150a5 | |||
| f98db6d21c | |||
| c695dfd92e | |||
| ffd78d76e1 | |||
| e479c41667 | |||
| 9f8c481992 | |||
| 3320d12994 | |||
| be6f522cf3 | |||
| b0b6871bbb | |||
| 59ae6217cd | |||
| 334cd7ad51 | |||
| 501c3680d9 | |||
| ebcc81c1ee | |||
| 6814372a89 | |||
| d5d14b7efc | |||
| 3a72686774 | |||
| aa73c5ed53 | |||
| cc0a385c22 | |||
| 0b8c9713e6 | |||
| e400a94ffb | |||
| 136ad3b0b5 | |||
| f9826104d8 | |||
| c0c97b76fb | |||
| a908e4d4b1 | |||
| e5c255200c | |||
| 00db4f5ed9 | |||
| 29ead3ff3e | |||
| 055074246e | |||
| 4bbe51fb4b | |||
| 841224372b | |||
| d1f0fa1a47 | |||
| 6fecf8bb01 | |||
| 6d44f02a38 | |||
| 1458e486d7 | |||
| dc29822e69 | |||
| dae7722da1 | |||
| 16d978dc58 | |||
| 5d3c154b45 | |||
| 00a8ef63b6 | |||
| 6ac437a3a5 | |||
| 33b24eba01 | |||
| 3a99c6e5f5 | |||
| 4c5d2839bd | |||
| 85b104bafa | |||
| 74e5d03a78 | |||
| cc43324ede | |||
| e4f9e1000d | |||
| 62829b0698 | |||
| 2551e990cb | |||
| 45c34319b5 | |||
| 75dcc566b3 | |||
| 4f1047e853 | |||
| 79f765c961 | |||
| eead2fad2c | |||
| 455c9e09ab | |||
| 4665c3565c | |||
| 7456b4b4ad | |||
| 32a6454065 | |||
| c52640c672 | |||
| d62ef17290 | |||
| 216af6a662 | |||
| 35d860427e | |||
| 9206574bae | |||
| 9c6f54131f | |||
| d67b95c593 | |||
| 2bf2f1b822 | |||
| 9ad94eccad | |||
| 6e8a900f25 | |||
| d9aa9e4480 | |||
| fe74818a37 | |||
| 7335126064 | |||
| 945dd71251 | |||
| 652aa29370 | |||
| 7034e2015e | |||
| 0a890ad871 | |||
| b52bb1124e | |||
| 41f33af51b | |||
| 6b4763c7da | |||
| be07889a45 | |||
| 1b3243c09c | |||
| fee1c9eccf | |||
| 084f6c31cb | |||
| 592bf76eb0 | |||
| 6f0aee1cc5 | |||
| 3575e20137 | |||
| f69f529258 | |||
| 3e7416ca7d | |||
| cf324c5d8c | |||
| 9da883a50c | |||
| ea3e03aaba | |||
| 417ce4b470 | |||
| 48deaa5f57 | |||
| a4fa163333 | |||
| 635d228c86 | |||
| 303d03d43c | |||
| 50f561dbd2 | |||
| 428d7ec94a |
22
DONATOR.MD
Normal file
22
DONATOR.MD
Normal file
@ -0,0 +1,22 @@
|
||||
# Donators
|
||||
|
||||
|
||||
| Name | Channel | Amount
|
||||
|---|---|---
|
||||
|[hailaz](https://gitee.com/hailaz)|gitee|¥20.00
|
||||
|[ireadx](https://github.com/ireadx)|alipay|¥201.00
|
||||
|[mg91](https://gitee.com/mg91)|gitee|¥10.00
|
||||
|[pibigstar](https://github.com/pibigstar)|alipay|¥10.00
|
||||
|[tiangenglan](https://gitee.com/tiangenglan)|gitee|¥30.00
|
||||
|[wxkj](https://gitee.com/wxkj)|wechat|¥10.00
|
||||
|[zhuhuan12](https://gitee.com/zhuhuan12)|gitee|¥50.00
|
||||
|[zfan_codes](https://gitee.com/zfan_codes)|gitee|¥10.00
|
||||
|[arden](https://github.com/arden)|alipay|¥10.00
|
||||
|潘兄|wechat|¥100.00
|
||||
|Fly的狐狸|wechat|¥100.00
|
||||
|土豆相公|alipay|¥66.60
|
||||
|上海金保证网络科技|bank|¥2000.00
|
||||
|
||||
|
||||
|
||||
<img src="https://goframe.org/images/donate.png"/>
|
||||
48
README.MD
48
README.MD
@ -11,11 +11,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
GoFrame is a modular, loose-coupled, production-ready and most-powerful application development framework of golang. Providing a series of core components and dozens of practical modules, such as: cache, logging, containers, timer, validator, database orm, etc. Supporting web server integrated with router, cookie, session, logger, configure, template, https, hooks, rewrites and many more features.
|
||||
-->
|
||||
|
||||
`GF(GoFrame)` is a modular, loose-coupled, production-ready and most-powerful application development framework of golang. Providing a series of core components and dozens of practical modules, such as: memcache, configure, validator, logging, array/queue/set/map containers, timer/timing tasks, file/memory lock, object pool, database ORM, etc. Supporting web server integrated with router, cookie, session, logger, template, https, hooks, rewrites and many more features.
|
||||
`GF(GoFrame)` is a modular, full-featured and production-ready application development framework of golang. Providing a series of core components and dozens of practical modules, such as: memcache, configure, validator, logging, array/queue/set/map containers, timer/timing tasks, file/memory lock, object pool, database ORM, etc. Supporting web server integrated with router, cookie, session, logger, template, https, hooks, rewrites and many more features.
|
||||
|
||||
|
||||
# Installation
|
||||
@ -68,50 +64,18 @@ func main() {
|
||||
|
||||
`GF` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
|
||||
|
||||
# Contributors
|
||||
|
||||
- [aloncn](https://github.com/aloncn)
|
||||
- [chenyang351](https://github.com/chenyang351)
|
||||
- [garfieldkwong](https://gitee.com/garfieldkwong)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [johng](https://johng.cn)
|
||||
- [jroam](https://github.com/jroam)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [touzijiao](https://github.com/touzijiao)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
- [youyixiao](https://github.com/youyixiao)
|
||||
- [zhangjinfu](https://gitee.com/zhangjinfu)
|
||||
- [zhaopengme](https://github.com/zhaopengme)
|
||||
- [zseeker](https://gitee.com/zseeker)
|
||||
|
||||
# Donators
|
||||
|
||||
We currently accept donation by Alipay/WechatPay, please note your github/gitee account in your payment bill. If you like `GF`, why not [buy developer a cup of coffee](https://goframe.org/images/donate.png)?
|
||||
|
||||
- [flyke-xu](https://gitee.com/flyke-xu)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [ireadx](https://github.com/ireadx)
|
||||
- [mg91](https://gitee.com/mg91)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [tiangenglan](https://gitee.com/tiangenglan)
|
||||
- [wxkj](https://gitee.com/wxkj)
|
||||
- [zhuhuan12](https://gitee.com/zhuhuan12)
|
||||
- [zfan_codes](https://gitee.com/zfan_codes)
|
||||
|
||||
|
||||
|
||||
|
||||
We currently accept donation by Alipay/WechatPay, please note your github/gitee account in your payment bill. If you like `GF`, why not [buy developer a cup of coffee](DONATOR.MD)?
|
||||
|
||||
# Thanks
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/images/jetbrains.png" width="100" alt="JetBrains"/></a>
|
||||
|
||||
|
||||
<!--
|
||||
# Sponsor
|
||||
|
||||
We appreciate any kind of sponsorship for `GF` development. If you've got some interested, please contact john@goframe.org.
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
44
README_ZH.MD
44
README_ZH.MD
@ -11,13 +11,13 @@
|
||||
|
||||
</div>
|
||||
|
||||
`GF(Go Frame)`是一款模块化、松耦合、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、
|
||||
`GF(Go Frame)`是一款模块化、高性能、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、
|
||||
并发安全容器等等。并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、服务注册、配置管理、模板引擎等等,支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。
|
||||
|
||||
|
||||
# 特点
|
||||
* 模块化、松耦合设计;
|
||||
* 丰富实用的开发模块;
|
||||
* 模块丰富,开箱即用;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 致力于项目的通用方案;
|
||||
@ -79,42 +79,8 @@ func main() {
|
||||
|
||||
# 捐赠
|
||||
|
||||
如果您喜欢`GF`,要不[给开发者来杯咖啡吧](https://goframe.org/images/donate.png)!
|
||||
如果您喜欢`GF`,要不[给开发者来杯咖啡吧](DONATOR.MD)!
|
||||
请在捐赠时备注您的`github`/`gitee`账号名称。
|
||||
|
||||
# 赞助
|
||||
|
||||
赞助支持`GF`框架的快速研发,如果您感兴趣,请联系 john@goframe.org 。
|
||||
|
||||
# 贡献者
|
||||
|
||||
- [aloncn](https://github.com/aloncn)
|
||||
- [chenyang351](https://github.com/chenyang351)
|
||||
- [garfieldkwong](https://gitee.com/garfieldkwong)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [johng](https://johng.cn)
|
||||
- [jroam](https://github.com/jroam)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [touzijiao](https://github.com/touzijiao)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
- [youyixiao](https://github.com/youyixiao)
|
||||
- [zhangjinfu](https://gitee.com/zhangjinfu)
|
||||
- [zhaopengme](https://github.com/zhaopengme)
|
||||
- [zseeker](https://gitee.com/zseeker)
|
||||
|
||||
# 捐赠者
|
||||
|
||||
- [flyke-xu](https://gitee.com/flyke-xu)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [ireadx](https://github.com/ireadx)
|
||||
- [mg91](https://gitee.com/mg91)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [tiangenglan](https://gitee.com/tiangenglan)
|
||||
- [wxkj](https://gitee.com/wxkj)
|
||||
- [zhuhuan12](https://gitee.com/zhuhuan12)
|
||||
- [zfan_codes](https://gitee.com/zfan_codes)
|
||||
|
||||
# 感谢
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/images/jetbrains.png" width="100" alt="JetBrains"/></a>
|
||||
60
RELEASE.MD
60
RELEASE.MD
@ -1,3 +1,63 @@
|
||||
# `v1.7.0`
|
||||
## 新功能/改进
|
||||
1. 重构改进`glog`模块:
|
||||
- 去掉日志模块所有的锁机制,改为无锁设计,执行性能更加高效
|
||||
- 增加日志内容的异步输出特性:https://goframe.org/os/glog/async
|
||||
- 增加日志输出内容的`Json`格式支持:https://goframe.org/os/glog/json
|
||||
- 增加`Flags`额外特性支持,包括文件行号打印、自定义时间格式、异步输出等特性控制:https://goframe.org/os/glog/flags
|
||||
- 增加`Writer`接口支持,便于开发者进行自定义的日志功能扩展,或者与第三方服务/模块对接集成:https://goframe.org/os/glog/writer
|
||||
- 修改`SetStdPrint`方法名为`SetStdoutPrint`
|
||||
- 修改链式方法`StdPrint`方法名为`Stdout`
|
||||
- 标记淘汰`*fln`日志输出方法,`*f`方法支持自动的换行输出
|
||||
- 新增更多的链式方法支持:https://goframe.org/os/glog/chain
|
||||
1. 重构改进`gmap`模块:
|
||||
- 增加更多数据格式支持:`HashMap`/`ListMap`/`TreeMap`
|
||||
- 简化类型名称,如`gmap.StringInterfaceMap`简化为`gmap.StrAnyMap`
|
||||
- 改进`Map/Keys/Values`方法以提高性能
|
||||
- 修改`BatchSet`/`BatchRemove`方法名为`Sets`/`Removes`
|
||||
- 新增更多功能方法支持:https://goframe.org/container/gmap/index
|
||||
1. 改进`gtime`时间模块:
|
||||
- 增加并完善更多的类`PHP`时间格式支持
|
||||
- 新增更多功能方法,如`FormatTo`/`LayoutTo`等等
|
||||
- 详见开发文档:https://goframe.org/os/gtime/index
|
||||
1. 改进`gdb`数据库模块:
|
||||
- 增加对继承结构体的数据转换支持:https://goframe.org/database/gdb/senior
|
||||
- 新增`GetLastSql`方法,用以在调试模式下获取最近一条执行的SQL语句
|
||||
- 其他的细节处理改进
|
||||
1. 改进`gtcp`通信模块:
|
||||
- 完善处理细节,提高通信性能;
|
||||
- 增加`TLS`服务端/客户端通信支持:https://goframe.org/net/gtcp/tls
|
||||
- 增加简单协议支持,便于开发者封包/解包,并解决粘包/半包问题:https://goframe.org/net/gtcp/conn/pkg
|
||||
- TCP服务端增加`Close`方法
|
||||
- 更多细节查看开发文档:https://goframe.org/net/gtcp/index
|
||||
1. 改进`gconv`类型转换模块
|
||||
- 修改`gconv.TimeDuration`转换方法名称为`gconv.Duration`
|
||||
- 新增`gconv.StructDeep`及`gconv.MapDeep`方法,支持递归转换
|
||||
- 详见开发文档:https://goframe.org/util/gconv/struct
|
||||
1. 改进`ghttp`模块:
|
||||
- 日志输出增加`http/https`字段:https://goframe.org/net/ghttp/logs
|
||||
- 新增`ghttp.Server.SetKeepAlive`设置方法,用以开启/关闭`KeepAlive`特性
|
||||
- 增加`ghttp.Request.GetUrl`方法,用以获取当前完整的URL请求地址
|
||||
- `ghttp.Client`客户端支持开发者自定义`Transport`属性,`ghttp.Client.Post`方法支持`浏览器模式`:https://goframe.org/net/ghttp/client
|
||||
1. 新增`gtree`树形数据结构容器支持:https://goframe.org/container/gtree/index
|
||||
1. 改进`gudp`通信模块,具体请参考开发文档:https://goframe.org/net/gudp/index
|
||||
1. 改进`gcfg`配置管理模块,所有`Get*`方法增加默认值支持:https://goframe.org/os/gcfg/index
|
||||
1. `gredis`模块新增`DoVar`/`ReceiveVar`方法以便于开发者对执行结果进行灵活的数据格式转换:https://goframe.org/database/gredis/index
|
||||
1. `gcache`模块`BatchSet`/`BatchRemove`方法名修改为`Sets`/`Removes`
|
||||
1. 改进`gjson`/`gparser`模块,增加更多方法:https://goframe.org/encoding/gjson/index
|
||||
1. 改进`gfile.MainPkgPath`方法,以支持不同平台的开发环境;
|
||||
1. 改进`grpool`协程池模块,提高执行性能:https://goframe.org/os/grpool/index
|
||||
1. 改进`TryCatch`方法,当开发者不传递`Catch`参数时,默认抑制并忽略错误的处理
|
||||
1. 改进`gmlock`模块,增加`TryLockFunc`/`TryRLockFunc`方法,并且为`gmlock.Mutex`高级互斥锁对象增加`TryLockFunc`/`TryRLockFunc`方法
|
||||
1. 去除`gvar.VarRead`接口类型支持
|
||||
|
||||
## Bug Fix
|
||||
1. 解决`gdb`模块与其他第三方`ORM`模块同时使用的冲突;
|
||||
1. 修复`gcron.AddOnce`方法的细节逻辑问题;
|
||||
1. 修复内部`empty`模块的`IsEmpty`方法对结构体属性的空校验错误;
|
||||
1. 修复`gview`模板引擎的并发安全问题;
|
||||
1. 修复`ghttp.Server`的SESSION初始化过期时间问题;
|
||||
|
||||
# `v1.6.0` (2019-04-09)
|
||||
|
||||
## 新功能/改进
|
||||
|
||||
9
TODO.MD
9
TODO.MD
@ -6,7 +6,6 @@
|
||||
1. orm增加sqlite对Save方法的支持(去掉触发器语句);
|
||||
1. ghttp.Server增加Ip访问控制功能(DenyIps&AllowIps);
|
||||
1. ghttp增加返回数据压缩机制;
|
||||
1. gview中的template标签失效问题;
|
||||
1. ghttp.Server增加proxy功能特性,本地proxy和远程proxy,本地即将路由规则映射;远程即反向代理;
|
||||
1. gjson对大json数据的解析效率问题;
|
||||
1. ghttp增加route name特性,并同时支持backend和template(提供内置函数)引用,可以通过RedirectRoute方法给定route name和路由参数跳转到指定的路由地址上;
|
||||
@ -46,6 +45,11 @@
|
||||
1. gset.Add/Remove/Contains方法增加批量操作支持;
|
||||
1. gmlock增加手动清理机制:当内存锁不再使用时,由调用端决定是否清理内存锁;
|
||||
1. gtimer增加DelayAdd*方法返回Entry对象,以便DelayAdd*的定时任务也能进行状态控制;gcron同理需要改进;
|
||||
1. 改进gdb对pgsql/mssql/oracle的支持,使用方法覆盖的方式改进操作,而不是完全依靠正则替换的方式;
|
||||
1. gdb的Cache缓存功能增加可自定义缓存接口,以便支持外部缓存功能,缓存接口可以通过io.ReadWriter接口实现;
|
||||
1. grpool增加支持阻塞添加任务接口;
|
||||
|
||||
|
||||
|
||||
# DONE
|
||||
1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换;
|
||||
@ -119,4 +123,5 @@
|
||||
1. gfile对于文件的读写强行使用了gfpool,在某些场景下不合适,需要考虑剥离开,并为开发者提供单独的指针池文件操作特性;
|
||||
1. ghttp.Client自动Close机制;
|
||||
1. ghttp路由功能增加分组路由特性;
|
||||
1. 增加可选择性的orm tag特性,用以数据表记录与struct对象转换的键名属性映射;
|
||||
1. 增加可选择性的orm tag特性,用以数据表记录与struct对象转换的键名属性映射;
|
||||
1. gview中的template标签失效问题;
|
||||
@ -22,14 +22,14 @@ type IntArray struct {
|
||||
}
|
||||
|
||||
// NewIntArray creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArray(unsafe...bool) *IntArray {
|
||||
return NewIntArraySize(0, 0, unsafe...)
|
||||
}
|
||||
|
||||
// NewIntArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -39,7 +39,7 @@ func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
|
||||
return &IntArray{
|
||||
@ -49,7 +49,7 @@ func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntArrayFromCopy(array []int, unsafe...bool) *IntArray {
|
||||
newArray := make([]int, len(array))
|
||||
@ -110,7 +110,7 @@ func (a *IntArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *IntArray) Sort(reverse...bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -22,7 +22,7 @@ type Array struct {
|
||||
}
|
||||
|
||||
// New creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(unsafe...bool) *Array {
|
||||
return NewArraySize(0, 0, unsafe...)
|
||||
@ -34,7 +34,7 @@ func NewArray(unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArraySize(size int, cap int, unsafe...bool) *Array {
|
||||
return &Array{
|
||||
@ -54,7 +54,7 @@ func NewFromCopy(array []interface{}, unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
|
||||
return &Array{
|
||||
@ -64,7 +64,7 @@ func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
|
||||
}
|
||||
|
||||
// NewArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewArrayFromCopy(array []interface{}, unsafe...bool) *Array {
|
||||
newArray := make([]interface{}, len(array))
|
||||
|
||||
@ -23,14 +23,14 @@ type StringArray struct {
|
||||
}
|
||||
|
||||
// NewStringArray creates and returns an empty array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArray(unsafe...bool) *StringArray {
|
||||
return NewStringArraySize(0, 0, unsafe...)
|
||||
}
|
||||
|
||||
// NewStringArraySize create and returns an array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
|
||||
return &StringArray{
|
||||
@ -40,7 +40,7 @@ func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
|
||||
}
|
||||
|
||||
// NewStringArrayFrom creates and returns an array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
|
||||
return &StringArray {
|
||||
@ -50,7 +50,7 @@ func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
|
||||
}
|
||||
|
||||
// NewStringArrayFromCopy creates and returns an array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringArrayFromCopy(array []string, unsafe...bool) *StringArray {
|
||||
newArray := make([]string, len(array))
|
||||
@ -111,7 +111,7 @@ func (a *StringArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *StringArray) Sort(reverse...bool) *StringArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -26,14 +26,14 @@ type SortedIntArray struct {
|
||||
}
|
||||
|
||||
// NewSortedIntArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArray(unsafe...bool) *SortedIntArray {
|
||||
return NewSortedIntArraySize(0, unsafe...)
|
||||
}
|
||||
|
||||
// NewSortedIntArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
|
||||
return &SortedIntArray {
|
||||
@ -53,7 +53,7 @@ func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
|
||||
a := NewSortedIntArraySize(0, unsafe...)
|
||||
@ -63,15 +63,12 @@ func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
|
||||
}
|
||||
|
||||
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedIntArrayFromCopy(array []int, unsafe...bool) *SortedIntArray {
|
||||
newArray := make([]int, len(array))
|
||||
copy(newArray, array)
|
||||
return &SortedIntArray{
|
||||
mu : rwmutex.New(unsafe...),
|
||||
array : newArray,
|
||||
}
|
||||
return NewSortedIntArrayFrom(newArray, unsafe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -84,7 +81,7 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedIntArray) Sort() *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
@ -280,17 +277,23 @@ func (a *SortedIntArray) Slice() []int {
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedIntArray) Contains(value int) bool {
|
||||
return a.Search(value) == 0
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedIntArray) Search(value int) (index int) {
|
||||
index, _ = a.binSearch(value, true)
|
||||
return
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int) {
|
||||
if len(a.array) == 0 {
|
||||
return -1, -2
|
||||
|
||||
@ -26,8 +26,8 @@ type SortedArray struct {
|
||||
}
|
||||
|
||||
// NewSortedArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety, which is false in default.
|
||||
// The param <comparator> used to compare values to sort in array,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety, which is false in default.
|
||||
// The parameter <comparator> used to compare values to sort in array,
|
||||
// if it returns value < 0, means v1 < v2;
|
||||
// if it returns value = 0, means v1 = v2;
|
||||
// if it returns value > 0, means v1 > v2;
|
||||
@ -36,19 +36,19 @@ func NewSortedArray(comparator func(v1, v2 interface{}) int, unsafe...bool) *Sor
|
||||
}
|
||||
|
||||
// NewSortedArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArraySize(cap int, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
return &SortedArray{
|
||||
mu : rwmutex.New(unsafe...),
|
||||
unique : gtype.NewBool(),
|
||||
array : make([]interface{}, 0, cap),
|
||||
mu : rwmutex.New(unsafe...),
|
||||
unique : gtype.NewBool(),
|
||||
array : make([]interface{}, 0, cap),
|
||||
comparator : comparator,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFrom(array []interface{}, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
a := NewSortedArraySize(0, comparator, unsafe...)
|
||||
@ -60,15 +60,12 @@ func NewSortedArrayFrom(array []interface{}, comparator func(v1, v2 interface{})
|
||||
}
|
||||
|
||||
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedArrayFromCopy(array []interface{}, unsafe...bool) *SortedArray {
|
||||
func NewSortedArrayFromCopy(array []interface{}, comparator func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
|
||||
newArray := make([]interface{}, len(array))
|
||||
copy(newArray, array)
|
||||
return &SortedArray{
|
||||
mu : rwmutex.New(unsafe...),
|
||||
array : newArray,
|
||||
}
|
||||
return NewSortedArrayFrom(newArray, comparator, unsafe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -83,7 +80,7 @@ func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
func (a *SortedArray) Sort() *SortedArray {
|
||||
a.mu.Lock()
|
||||
@ -281,17 +278,23 @@ func (a *SortedArray) Slice() []interface{} {
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedArray) Contains(value interface{}) bool {
|
||||
return a.Search(value) == 0
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedArray) Search(value interface{}) (index int) {
|
||||
index, _ = a.binSearch(value, true)
|
||||
return
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
func (a *SortedArray) binSearch(value interface{}, lock bool)(index int, result int) {
|
||||
if len(a.array) == 0 {
|
||||
return -1, -2
|
||||
|
||||
@ -27,14 +27,14 @@ type SortedStringArray struct {
|
||||
}
|
||||
|
||||
// NewSortedStringArray creates and returns an empty sorted array.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArray(unsafe...bool) *SortedStringArray {
|
||||
return NewSortedStringArraySize(0, unsafe...)
|
||||
}
|
||||
|
||||
// NewSortedStringArraySize create and returns an sorted array with given size and cap.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
|
||||
return &SortedStringArray {
|
||||
@ -48,7 +48,7 @@ func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
|
||||
}
|
||||
|
||||
// NewSortedStringArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray {
|
||||
a := NewSortedStringArraySize(0, unsafe...)
|
||||
@ -58,15 +58,12 @@ func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray
|
||||
}
|
||||
|
||||
// NewSortedStringArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
|
||||
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using array in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewSortedStringArrayFromCopy(array []string, unsafe...bool) *SortedStringArray {
|
||||
newArray := make([]string, len(array))
|
||||
copy(newArray, array)
|
||||
return &SortedStringArray{
|
||||
mu : rwmutex.New(unsafe...),
|
||||
array : newArray,
|
||||
}
|
||||
return NewSortedStringArrayFrom(newArray, unsafe...)
|
||||
}
|
||||
|
||||
// SetArray sets the underlying slice array with the given <array>.
|
||||
@ -79,7 +76,7 @@ func (a *SortedStringArray) SetArray(array []string) *SortedStringArray {
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The param <reverse> controls whether sort
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order.
|
||||
func (a *SortedStringArray) Sort() *SortedStringArray {
|
||||
a.mu.Lock()
|
||||
@ -275,17 +272,23 @@ func (a *SortedStringArray) Slice() []string {
|
||||
|
||||
// Contains checks whether a value exists in the array.
|
||||
func (a *SortedStringArray) Contains(value string) bool {
|
||||
return a.Search(value) == 0
|
||||
return a.Search(value) != -1
|
||||
}
|
||||
|
||||
// Search searches array by <value>, returns the index of <value>,
|
||||
// or returns -1 if not exists.
|
||||
func (a *SortedStringArray) Search(value string) (index int) {
|
||||
index, _ = a.binSearch(value, true)
|
||||
return
|
||||
if i, r := a.binSearch(value, true); r == 0 {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Binary search.
|
||||
// It returns the last compared index and the result.
|
||||
// If <result> equals to 0, it means the value at <index> is equals to <value>.
|
||||
// If <result> lesser than 0, it means the value at <index> is lesser than <value>.
|
||||
// If <result> greater than 0, it means the value at <index> is greater than <value>.
|
||||
func (a *SortedStringArray) binSearch(value string, lock bool) (index int, result int) {
|
||||
if len(a.array) == 0 {
|
||||
return -1, -2
|
||||
|
||||
@ -9,35 +9,35 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
sortedIntArray = garray.NewSortedIntArray()
|
||||
sortedIntArray = garray.NewSortedIntArray()
|
||||
)
|
||||
|
||||
func BenchmarkSortedIntArray_Add(b *testing.B) {
|
||||
b.N = 1000
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.Add(i)
|
||||
}
|
||||
b.N = 1000
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.Add(i)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSortedIntArray_Search(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.Search(i)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.Search(i)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSortedIntArray_PopLeft(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.PopLeft()
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.PopLeft()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSortedIntArray_PopRight(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.PopLeft()
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
sortedIntArray.PopLeft()
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,75 +9,86 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_IntArray_Unique(t *testing.T) {
|
||||
expect := []int{1, 2, 3, 4, 5, 6}
|
||||
array := garray.NewIntArray()
|
||||
array.Append(1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6)
|
||||
array.Unique()
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []int{1, 2, 3, 4, 5, 6}
|
||||
array := garray.NewIntArray()
|
||||
array.Append(1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6)
|
||||
array.Unique()
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedIntArray1(t *testing.T) {
|
||||
expect := []int{0,1,2,3,4,5,6,7,8,9,10}
|
||||
array := garray.NewSortedIntArray()
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(i)
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
array := garray.NewSortedIntArray()
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(i)
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedIntArray2(t *testing.T) {
|
||||
expect := []int{0,1,2,3,4,5,6,7,8,9,10}
|
||||
array := garray.NewSortedIntArray()
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(i)
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
array := garray.NewSortedIntArray()
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(i)
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedStringArray1(t *testing.T) {
|
||||
expect := []string{"0","1","10","2","3","4","5","6","7","8","9"}
|
||||
array := garray.NewSortedStringArray()
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedStringArray()
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedStringArray2(t *testing.T) {
|
||||
expect := []string{"0","1","10","2","3","4","5","6","7","8","9"}
|
||||
array := garray.NewSortedStringArray()
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedStringArray()
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedArray1(t *testing.T) {
|
||||
expect := []string{"0","1","10","2","3","4","5","6","7","8","9"}
|
||||
array := garray.NewSortedArray(func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
})
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedArray(func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
})
|
||||
for i := 10; i > -1; i-- {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func Test_SortedArray2(t *testing.T) {
|
||||
expect := []string{"0","1","10","2","3","4","5","6","7","8","9"}
|
||||
array := garray.NewSortedArray(func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
})
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
expect := []string{"0", "1", "10", "2", "3", "4", "5", "6", "7", "8", "9"}
|
||||
array := garray.NewSortedArray(func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
})
|
||||
for i := 0; i <= 10; i++ {
|
||||
array.Add(gconv.String(i))
|
||||
}
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
}
|
||||
|
||||
func TestNewFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"100", "200", "300", "400", "500", "600"}
|
||||
array1 := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array1.PopRands(2), a1)
|
||||
gtest.Assert(len(array1.PopRands(1)), 1)
|
||||
gtest.Assert(len(array1.PopRands(9)), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,193 +9,602 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_IntArray_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []int{0, 1, 2, 3}
|
||||
expect2 := []int{3, 2, 1, 0}
|
||||
array := garray.NewIntArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.Sort()
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.Sort(true)
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []int{0, 1, 2, 3}
|
||||
expect2 := []int{3, 2, 1, 0}
|
||||
array := garray.NewIntArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.Sort()
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.Sort(true)
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Unique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{1, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []int{1, 2, 3})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{1, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []int{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_PushAndPop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []int{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []int{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []int{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []int{0, 1, 2, 3}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []int{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []int{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []int{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []int{0,1,2,3,4,5,6}
|
||||
value2 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(value1)
|
||||
array2 := garray.NewIntArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []int{0,1})
|
||||
gtest.Assert(array1.Slice(), []int{2,3,4,5,6})
|
||||
gtest.Assert(array1.PopRights(2), []int{5,6})
|
||||
gtest.Assert(array1.Slice(), []int{2,3,4})
|
||||
gtest.Assert(array1.PopRights(20), []int{2,3,4})
|
||||
gtest.Assert(array1.Slice(), []int{})
|
||||
gtest.Assert(array2.PopLefts(20), []int{0,1,2,3,4,5,6})
|
||||
gtest.Assert(array2.Slice(), []int{})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
value2 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(value1)
|
||||
array2 := garray.NewIntArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []int{0, 1})
|
||||
gtest.Assert(array1.Slice(), []int{2, 3, 4, 5, 6})
|
||||
gtest.Assert(array1.PopRights(2), []int{5, 6})
|
||||
gtest.Assert(array1.Slice(), []int{2, 3, 4})
|
||||
gtest.Assert(array1.PopRights(20), []int{2, 3, 4})
|
||||
gtest.Assert(array1.Slice(), []int{})
|
||||
gtest.Assert(array2.PopLefts(20), []int{0, 1, 2, 3, 4, 5, 6})
|
||||
gtest.Assert(array2.Slice(), []int{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []int{0})
|
||||
gtest.Assert(array1.Range(1, 2), []int{1})
|
||||
gtest.Assert(array1.Range(0, 2), []int{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []int{0})
|
||||
gtest.Assert(array1.Range(1, 2), []int{1})
|
||||
gtest.Assert(array1.Range(0, 2), []int{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6, 7}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []int{0,1,2,3,4,5,6,7})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6, 7}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []int{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Fill(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0}
|
||||
a2 := []int{0}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []int{0,100,100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []int{100,100})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0}
|
||||
a2 := []int{0}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := garray.NewIntArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []int{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []int{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1,2,3,4,5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []int{1,2})
|
||||
gtest.Assert(chunks[1], []int{3,4})
|
||||
gtest.Assert(chunks[2], []int{5})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []int{1, 2})
|
||||
gtest.Assert(chunks[1], []int{3, 4})
|
||||
gtest.Assert(chunks[2], []int{5})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Pad(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []int{0,1,1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []int{1,0,1,1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []int{1,0,1,1})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []int{0, 1, 1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []int{1, 0, 1, 1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []int{1, 0, 1, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []int{0,1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []int{2,3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []int{5,6})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []int{0, 1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []int{2, 3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []int{5, 6})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
gtest.AssertIN(array1.Rand(), a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
gtest.AssertIN(array1.Rand(), a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewIntArrayFrom(a1)
|
||||
ns1 := array.PopRands(2)
|
||||
gtest.AssertIN(ns1, []int{100, 200, 300, 400, 500, 600})
|
||||
gtest.AssertIN(len(ns1), 2)
|
||||
|
||||
ns2 := array.PopRands(7)
|
||||
gtest.AssertIN(len(ns2), 6)
|
||||
gtest.AssertIN(ns2, []int{100, 200, 300, 400, 500, 600})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Shuffle(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Reverse(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []int{6,5,4,3,2,1,0})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []int{6, 5, 4, 3, 2, 1, 0})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 5, 2, 1, 4, 3, 6}
|
||||
array1 := garray.NewSortedIntArrayFromCopy(a1, false)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.SetArray(a2)
|
||||
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2.Search(3), -1)
|
||||
gtest.Assert(array2.Search(5), 1)
|
||||
gtest.Assert(array2.Search(6), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1}
|
||||
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Sort()
|
||||
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []int{0, 1, 2, 3})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(0), 0)
|
||||
gtest.Assert(array1.Get(1), 1)
|
||||
gtest.Assert(array1.Get(3), 5)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.Remove(2)
|
||||
gtest.Assert(i1, 3)
|
||||
gtest.Assert(array1.Search(5), 2)
|
||||
|
||||
// 再次删除剩下的数组中的第一个
|
||||
i2 := array1.Remove(0)
|
||||
gtest.Assert(i2, 0)
|
||||
gtest.Assert(array1.Search(5), 1)
|
||||
|
||||
a2 := []int{1, 3, 4}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
i3 := array2.Remove(1)
|
||||
gtest.Assert(array2.Search(1), 0)
|
||||
gtest.Assert(i3, 3)
|
||||
i3 = array2.Remove(1)
|
||||
gtest.Assert(array2.Search(4), -1)
|
||||
gtest.Assert(i3, 4)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopLeft()
|
||||
gtest.Assert(i1, 1)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(1), -1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRight()
|
||||
gtest.Assert(i1, 5)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(5), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRand()
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(i1), -1)
|
||||
gtest.AssertIN(i1, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRands(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.AssertIN(ns1, []int{1, 3, 5, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRands(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.Assert(len(ns2), 4)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopLefts(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{1, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopLefts(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRights(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{3, 5})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRights(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2, 6, 7}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Range(1, 4)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1, []int{2, 3, 5})
|
||||
|
||||
ns2 := array1.Range(5, 4)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.Range(-1, 4)
|
||||
gtest.Assert(len(ns3), 4)
|
||||
|
||||
nsl := array1.Range(5, 8)
|
||||
gtest.Assert(len(nsl), 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
n1 := array1.Sum()
|
||||
gtest.Assert(n1, 9)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Contains(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
//gtest.Assert(array1.Contains(3),true) //todo 这一行应该返回true
|
||||
gtest.Assert(array1.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2, array1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Chunk(2) //按每几个元素切成一个数组
|
||||
ns2 := array1.Chunk(-1)
|
||||
t.Log(ns1)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1[0], []int{1, 2})
|
||||
gtest.Assert(ns1[2], []int{5})
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.SubSlice(1, 2)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
gtest.Assert(ns1, []int{2, 3})
|
||||
|
||||
ns2 := array1.SubSlice(7, 2)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.SubSlice(3, 5)
|
||||
gtest.Assert(len(ns3), 2)
|
||||
gtest.Assert(ns3, []int{4, 5})
|
||||
|
||||
ns4 := array1.SubSlice(3, 1)
|
||||
gtest.Assert(len(ns4), 1)
|
||||
gtest.Assert(ns4, []int{4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rand() //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rands(2) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
|
||||
ns2 := array1.Rands(6) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns2, a1)
|
||||
gtest.Assert(len(ns2), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.CountValues() //按每几个元素切成一个数组
|
||||
gtest.Assert(len(ns1), 5)
|
||||
gtest.Assert(ns1[2], 1)
|
||||
gtest.Assert(ns1[3], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.SetUnique(true)
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(array1, []int{1, 2, 3, 4, 5})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
a2 := []int{6, 7}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1, []int{6, 7})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Replace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
a2 := []int{6, 7}
|
||||
a3 := []int{9, 10, 11, 12, 13}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array1.Replace(a2)
|
||||
gtest.Assert(array1, []int{6, 7, 3, 5})
|
||||
|
||||
array1.Replace(a3)
|
||||
gtest.Assert(array1, []int{9, 10, 11, 12})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array1, array2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(2), 3)
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Sum(), 11)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5, 3}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(len(m1), 4)
|
||||
gtest.Assert(m1[1], 1)
|
||||
gtest.Assert(m1[3], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewIntArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5, 3}
|
||||
array1 := garray.NewIntArrayFromCopy(a1)
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(array1, a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 5, 4}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
n1 := array1.Remove(1)
|
||||
gtest.Assert(n1, 2)
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
|
||||
n1 = array1.Remove(0)
|
||||
gtest.Assert(n1, 1)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
|
||||
n1 = array1.Remove(2)
|
||||
gtest.Assert(n1, 4)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,196 +9,670 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Array_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []interface{}{0, 1, 2, 3}
|
||||
expect2 := []interface{}{3, 2, 1, 0}
|
||||
array := garray.NewArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) < v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) > v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []interface{}{0, 1, 2, 3}
|
||||
expect2 := []interface{}{3, 2, 1, 0}
|
||||
array := garray.NewArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) < v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) > v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Unique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{1, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []interface{}{1, 2, 3})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{1, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []interface{}{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PushAndPop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []interface{}{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0,1,2,3,4,5,6}
|
||||
value2 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{0,1})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2,3,4,5,6})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{5,6})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2,3,4})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{2,3,4})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{0,1,2,3,4,5,6})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
value2 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4, 5, 6})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{0, 1, 2, 3, 4, 5, 6})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{0})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{1})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{0})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{1})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []interface{}{0,1,2,3,4,5,6,7})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []interface{}{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Fill(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0,100,100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100,100})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{1,2,3,4,5}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []interface{}{1,2})
|
||||
gtest.Assert(chunks[1], []interface{}{3,4})
|
||||
gtest.Assert(chunks[2], []interface{}{5})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []interface{}{1, 2})
|
||||
gtest.Assert(chunks[1], []interface{}{3, 4})
|
||||
gtest.Assert(chunks[2], []interface{}{5})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Pad(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{0,1,1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []interface{}{1,0,1,1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{1,0,1,1})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{0, 1, 1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []interface{}{0,1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []interface{}{2,3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []interface{}{5,6})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []interface{}{2, 3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []interface{}{5, 6})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Shuffle(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Reverse(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []interface{}{6,5,4,3,2,1,0})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []interface{}{6, 5, 4, 3, 2, 1, 0})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0,1,2,3,4,5,6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Replace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"m", "n", "p", "z", "x", "y", "d", "u"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Replace(a2)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
gtest.Assert(array2.Contains("b"), true)
|
||||
gtest.Assert(array2.Contains(4), true)
|
||||
gtest.Assert(array2.Contains("v"), false)
|
||||
array3 := array1.Replace(a3)
|
||||
gtest.Assert(array3.Len(), 7)
|
||||
gtest.Assert(array3.Contains(4), false)
|
||||
gtest.Assert(array3.Contains("p"), true)
|
||||
gtest.Assert(array3.Contains("u"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array1 = array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("b"), true)
|
||||
gtest.Assert(array1.Contains("5"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"a", "1", "2"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
array3 := garray.NewArrayFrom(a3)
|
||||
|
||||
gtest.Assert(array1.Sum(), 6)
|
||||
gtest.Assert(array2.Sum(), 0)
|
||||
gtest.Assert(array3.Sum(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array2.Sum(), 6)
|
||||
gtest.AssertEQ(array1, array2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "b", "c", "d", "e", "d"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.CountValues()
|
||||
gtest.Assert(len(array2), 5)
|
||||
gtest.Assert(array2["b"], 1)
|
||||
gtest.Assert(array2["d"], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_NewSortedArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
a2 := []interface{}{"h", "j", "i", "k"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
func2 := func(v1, v2 interface{}) int {
|
||||
return -1
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array2 := garray.NewSortedArrayFrom(a2, func2)
|
||||
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"a", "c", "f"})
|
||||
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []interface{}{"k", "i", "j", "h"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
func2 := func(v1, v2 interface{}) int {
|
||||
return -1
|
||||
}
|
||||
array1 := garray.NewSortedArrayFromCopy(a1, func1)
|
||||
array2 := garray.NewSortedArrayFromCopy(a1, func2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"a", "c", "f"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array2, []interface{}{"c", "f", "a"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
a2 := []interface{}{"e", "h", "g", "k"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1, []interface{}{"e", "g", "h", "k"})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array1.Sort()
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"a", "c", "f"})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
gtest.Assert(array1.Get(2), "f")
|
||||
gtest.Assert(array1.Get(1), "c")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Remove(1)
|
||||
gtest.Assert(gconv.String(i1), "b")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("b"), false)
|
||||
|
||||
i2 := array1.Remove(0)
|
||||
gtest.Assert(gconv.String(i2), "a")
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
|
||||
i3 := array1.Remove(1)
|
||||
gtest.Assert(gconv.String(i3), "d")
|
||||
gtest.Assert(array1.Len(), 1)
|
||||
gtest.Assert(array1.Contains("d"), false)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopLeft()
|
||||
gtest.Assert(gconv.String(i1), "a")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"b", "c", "d"})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRight()
|
||||
gtest.Assert(gconv.String(i1), "d")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"a", "b", "c"})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRand()
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRands(2)
|
||||
gtest.Assert(len(i1), 2)
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
|
||||
i2 := array1.PopRands(3)
|
||||
gtest.Assert(len(i1), 2)
|
||||
gtest.AssertIN(i2, []interface{}{"a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopLefts(2)
|
||||
gtest.Assert(len(i1), 2)
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c", "b", "e", "f"})
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
|
||||
i2 := array1.PopLefts(5)
|
||||
gtest.Assert(len(i2), 4)
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c", "b", "e", "f"})
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.PopRights(2)
|
||||
gtest.Assert(len(i1), 2)
|
||||
gtest.Assert(i1, []interface{}{"e", "f"})
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
|
||||
i2 := array1.PopRights(10)
|
||||
gtest.Assert(len(i2), 4)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Range(2, 5)
|
||||
gtest.Assert(i1, []interface{}{"c", "d", "e"})
|
||||
gtest.Assert(array1.Len(), 6)
|
||||
|
||||
i2 := array1.Range(7, 5)
|
||||
gtest.Assert(len(i2), 0)
|
||||
i2 = array1.Range(-1, 2)
|
||||
gtest.Assert(i2, []interface{}{"a", "b"})
|
||||
|
||||
i2 = array1.Range(4, 10)
|
||||
gtest.Assert(len(i2), 2)
|
||||
gtest.Assert(i2, []interface{}{"e", "f"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
a2 := []interface{}{"1", "2", "3", "b", "e", "f"}
|
||||
a3 := []interface{}{"4", "5", "6"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array2 := garray.NewSortedArrayFrom(a2, func1)
|
||||
array3 := garray.NewSortedArrayFrom(a3, func1)
|
||||
gtest.Assert(array1.Sum(), 0)
|
||||
gtest.Assert(array2.Sum(), 6)
|
||||
gtest.Assert(array3.Sum(), 15)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array1, array2)
|
||||
array1.Remove(1)
|
||||
gtest.AssertNE(array1, array2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e", "f"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
gtest.Assert(array1.Len(), 6)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Chunk(2)
|
||||
gtest.Assert(len(i1), 3)
|
||||
gtest.Assert(i1[0], []interface{}{"a", "b"})
|
||||
gtest.Assert(i1[2], []interface{}{"e"})
|
||||
|
||||
i1 = array1.Chunk(0)
|
||||
gtest.Assert(len(i1), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "b", "e"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.SubSlice(2, 3)
|
||||
gtest.Assert(len(i1), 3)
|
||||
gtest.Assert(i1, []interface{}{"c", "d", "e"})
|
||||
|
||||
i1 = array1.SubSlice(2, 6)
|
||||
gtest.Assert(len(i1), 3)
|
||||
gtest.Assert(i1, []interface{}{"c", "d", "e"})
|
||||
|
||||
i1 = array1.SubSlice(7, 2)
|
||||
gtest.Assert(len(i1), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Rand()
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
i1 := array1.Rands(2)
|
||||
gtest.AssertIN(i1, []interface{}{"a", "d", "c"})
|
||||
gtest.Assert(len(i1), 2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
|
||||
i1 = array1.Rands(4)
|
||||
gtest.Assert(len(i1), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
gtest.Assert(array1.Join(","), "a,c,d")
|
||||
gtest.Assert(array1.Join("."), "a.c.d")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(len(m1), 3)
|
||||
gtest.Assert(m1["c"], 2)
|
||||
gtest.Assert(m1["a"], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
array1.SetUnique(true)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1, []interface{}{"a", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,193 +9,631 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_StringArray_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, "100")
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search("100"), 0)
|
||||
gtest.Assert(array.Contains("100"), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains("100"), false)
|
||||
array.Append("4")
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, "100")
|
||||
array.InsertAfter(0, "200")
|
||||
gtest.Assert(array.Slice(), []string{"100", "200", "1", "2", "3", "4"})
|
||||
array.InsertBefore(5, "300")
|
||||
array.InsertAfter(6, "400")
|
||||
gtest.Assert(array.Slice(), []string{"100", "200", "1", "2", "3", "300", "4", "400"})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, "100")
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search("100"), 0)
|
||||
gtest.Assert(array.Contains("100"), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
gtest.Assert(array.Contains("100"), false)
|
||||
array.Append("4")
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, "100")
|
||||
array.InsertAfter(0, "200")
|
||||
gtest.Assert(array.Slice(), []string{"100", "200", "1", "2", "3", "4"})
|
||||
array.InsertBefore(5, "300")
|
||||
array.InsertAfter(6, "400")
|
||||
gtest.Assert(array.Slice(), []string{"100", "200", "1", "2", "3", "300", "4", "400"})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []string{"0", "1", "2", "3"}
|
||||
expect2 := []string{"3", "2", "1", "0"}
|
||||
array := garray.NewStringArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(gconv.String(i))
|
||||
}
|
||||
array.Sort()
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.Sort(true)
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []string{"0", "1", "2", "3"}
|
||||
expect2 := []string{"3", "2", "1", "0"}
|
||||
array := garray.NewStringArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(gconv.String(i))
|
||||
}
|
||||
array.Sort()
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.Sort(true)
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Unique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"1", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []string{"1", "2", "3"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"1", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []string{"1", "2", "3"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_PushAndPop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), "0")
|
||||
gtest.Assert(array.PopRight(), "3")
|
||||
gtest.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
gtest.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft("1").PushRight("2")
|
||||
gtest.Assert(array.Slice(), []string{"1", "2"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
expect := []string{"0", "1", "2", "3"}
|
||||
array := garray.NewStringArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), "0")
|
||||
gtest.Assert(array.PopRight(), "3")
|
||||
gtest.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
gtest.AssertIN(array.PopRand(), []string{"1", "2"})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft("1").PushRight("2")
|
||||
gtest.Assert(array.Slice(), []string{"1", "2"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []string{"0","1","2","3","4","5","6"}
|
||||
value2 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(value1)
|
||||
array2 := garray.NewStringArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{"0","1"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{"2","3","4","5","6"})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{"5","6"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{"2","3","4"})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{"2","3","4"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{"0","1","2","3","4","5","6"})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
value2 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(value1)
|
||||
array2 := garray.NewStringArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{"0", "1"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{"2", "3", "4", "5", "6"})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{"5", "6"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{"2", "3", "4"})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{"2", "3", "4"})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{"0", "1", "2", "3", "4", "5", "6"})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestString_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{"0"})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{"1"})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{"0", "1"})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
value1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(value1)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{"0"})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{"1"})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{"0", "1"})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3"}
|
||||
a2 := []string{"4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []string{"0","1","2","3","4","5","6","7"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3"}
|
||||
a2 := []string{"4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []string{"0", "1", "2", "3", "4", "5", "6", "7"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Fill(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0"}
|
||||
a2 := []string{"0"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, "100").Slice(), []string{"0","100","100"})
|
||||
gtest.Assert(array2.Fill(0, 2, "100").Slice(), []string{"100","100"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0"}
|
||||
a2 := []string{"0"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Fill(1, 2, "100").Slice(), []string{"0", "100", "100"})
|
||||
gtest.Assert(array2.Fill(0, 2, "100").Slice(), []string{"100", "100"})
|
||||
s1 := array2.Fill(-1, 2, "100")
|
||||
gtest.Assert(s1.Len(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"1","2","3","4","5"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []string{"1","2"})
|
||||
gtest.Assert(chunks[1], []string{"3","4"})
|
||||
gtest.Assert(chunks[2], []string{"5"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"1", "2", "3", "4", "5"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []string{"1", "2"})
|
||||
gtest.Assert(chunks[1], []string{"3", "4"})
|
||||
gtest.Assert(chunks[2], []string{"5"})
|
||||
gtest.Assert(len(array1.Chunk(0)), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Pad(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, "1").Slice(), []string{"0","1","1"})
|
||||
gtest.Assert(array1.Pad(-4, "1").Slice(), []string{"1","0","1","1"})
|
||||
gtest.Assert(array1.Pad(3, "1").Slice(), []string{"1","0","1","1"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, "1").Slice(), []string{"0", "1", "1"})
|
||||
gtest.Assert(array1.Pad(-4, "1").Slice(), []string{"1", "0", "1", "1"})
|
||||
gtest.Assert(array1.Pad(3, "1").Slice(), []string{"1", "0", "1", "1"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []string{"0","1"})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []string{"2","3"})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []string{"5","6"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []string{"0", "1"})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []string{"2", "3"})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []string{"5", "6"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), "2")
|
||||
gtest.Assert(len(array1.Rands(10)), "7")
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), "2")
|
||||
gtest.Assert(len(array1.Rands(10)), "7")
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
gtest.Assert(len(array1.Rand()), 1)
|
||||
gtest.AssertIN(array1.Rand(), a1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"100", "200", "300", "400", "500", "600"}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), a1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "b", "c", "d", "e", "f", "g"}
|
||||
a2 := []string{"1", "2", "3", "4", "5", "6", "7"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
//todo gtest.AssertIN(array1.PopRands(1),a1)
|
||||
gtest.AssertIN(array1.PopRands(1), strings.Join(a1, ","))
|
||||
gtest.AssertNI(array1.PopRands(1), strings.Join(a2, ","))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Shuffle(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Reverse(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []string{"6","5","4","3","2","1","0"})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []string{"6", "5", "4", "3", "2", "1", "0"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0","1","2","3","4","5","6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewStringArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
a2 := garray.NewStringArrayFromCopy(a1)
|
||||
a3 := garray.NewStringArrayFromCopy(a1, true)
|
||||
gtest.Assert(a2.Contains("1"), true)
|
||||
gtest.Assert(a2.Len(), 7)
|
||||
gtest.Assert(a2, a3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
a2 := []string{"a", "b", "c", "d"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Contains("2"), true)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
array1 = array1.SetArray(a2)
|
||||
gtest.Assert(array1.Contains("2"), false)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Replace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
a2 := []string{"a", "b", "c", "d"}
|
||||
a3 := []string{"o", "p", "q", "x", "y", "z", "w", "r", "v"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Contains("2"), true)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
array1 = array1.Replace(a2)
|
||||
gtest.Assert(array1.Contains("2"), false)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1.Contains("5"), true)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
array1 = array1.Replace(a3)
|
||||
gtest.Assert(array1.Contains("2"), false)
|
||||
gtest.Assert(array1.Contains("c"), false)
|
||||
gtest.Assert(array1.Contains("5"), false)
|
||||
gtest.Assert(array1.Contains("p"), true)
|
||||
gtest.Assert(array1.Contains("r"), false)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
a2 := []string{"0", "a", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := garray.NewStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Sum(), 21)
|
||||
gtest.Assert(array2.Sum(), 18)
|
||||
})
|
||||
}
|
||||
|
||||
//func TestStringArray_SortFunc(t *testing.T) {
|
||||
// gtest.Case(t, func() {
|
||||
// a1 := []string{"0","1","2","3","4","5","6"}
|
||||
// //a2 := []string{"0","a","3","4","5","6"}
|
||||
// array1 := garray.NewStringArrayFrom(a1)
|
||||
//
|
||||
// lesss:=func(v1,v2 string)bool{
|
||||
// if v1>v2{
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
// gtest.Assert(array1.Len(),7)
|
||||
// gtest.Assert(lesss("1","2"),false)
|
||||
// gtest.Assert(array1.SortFunc(lesss("1","2")) ,false)
|
||||
//
|
||||
//
|
||||
// })
|
||||
//}
|
||||
|
||||
func TestStringArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
str1 := array1.PopRand()
|
||||
gtest.Assert(strings.Contains("0,1,2,3,4,5,6", str1), true)
|
||||
gtest.Assert(array1.Len(), 6)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array2, array1)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "4", "6"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(len(m1), 6)
|
||||
gtest.Assert(m1["2"], 1)
|
||||
gtest.Assert(m1["4"], 2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStringArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStringArrayFrom(a1, true)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
s2 := garray.NewSortedStringArrayFrom(a1, false)
|
||||
gtest.Assert(s2, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStringArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStringArrayFromCopy(a1, true)
|
||||
gtest.Assert(s1.Len(), 4)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
a2 := []string{"f", "g", "h"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("d"), false)
|
||||
gtest.Assert(array1.Contains("b"), false)
|
||||
gtest.Assert(array1.Contains("g"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
array1.Sort() //todo 这个SortedStringArray.sort这个方法没有必要,
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(2), "c")
|
||||
gtest.Assert(array1.Get(0), "a")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Remove(2), "c")
|
||||
gtest.Assert(array1.Get(2), "d")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("c"), false)
|
||||
|
||||
gtest.Assert(array1.Remove(0), "a")
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
|
||||
// 此时array1里的元素只剩下2个
|
||||
gtest.Assert(array1.Remove(1), "d")
|
||||
gtest.Assert(array1.Len(), 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopLeft()
|
||||
gtest.Assert(s1, "a")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopRight()
|
||||
gtest.Assert(s1, "e")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("e"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopRand()
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains(s1), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopRands(2)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopRands(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopLefts(2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopLefts(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.PopRights(2)
|
||||
gtest.Assert(s1, []string{"f", "g"})
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(len(s1), 2)
|
||||
s1 = array1.PopRights(6)
|
||||
gtest.Assert(len(s1), 5)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d", "e"})
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.Range(2, 4)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"c", "d"})
|
||||
|
||||
s1 = array1.Range(-1, 2)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
|
||||
s1 = array1.Range(4, 8)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"e", "f", "g"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
a2 := []string{"1", "2", "3", "4", "a"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := garray.NewSortedStringArrayFrom(a2)
|
||||
gtest.Assert(array1.Sum(), 0)
|
||||
gtest.Assert(array2.Sum(), 10)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array1, array2)
|
||||
array1.Remove(1)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.SubSlice(1, 3)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"b", "c", "d"})
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
s2 := array1.SubSlice(1, 10)
|
||||
gtest.Assert(len(s2), 6)
|
||||
|
||||
s3 := array1.SubSlice(10, 2)
|
||||
gtest.Assert(len(s3), 0)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.AssertIN(array1.Rand(), []string{"e", "a", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
s1 := array1.Rands(2)
|
||||
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.Rands(4)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
gtest.Assert(array1.Join(","), "a,d,e")
|
||||
gtest.Assert(array1.Join("."), "a.d.e")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(m1["a"], 2)
|
||||
gtest.Assert(m1["d"], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := array1.Chunk(2)
|
||||
gtest.Assert(len(array2), 3)
|
||||
gtest.Assert(len(array2[0]), 2)
|
||||
gtest.Assert(array2[1], []string{"c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStringArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStringArrayFrom(a1)
|
||||
array2 := array1.SetUnique(true)
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []string{"a", "c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewStringArrayFrom(a1)
|
||||
s1 := array1.Remove(1)
|
||||
gtest.Assert(s1, "a")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
s1 = array1.Remove(3)
|
||||
gtest.Assert(s1, "c")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,59 +4,67 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gchan provides graceful channel for safe operations.
|
||||
// Package gchan provides graceful channel for no panic operations.
|
||||
//
|
||||
// It's safe to call Chan.Push/Close functions repeatedly.
|
||||
package gchan
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
)
|
||||
|
||||
// Graceful channel.
|
||||
type Chan struct {
|
||||
channel chan interface{}
|
||||
closed *gtype.Bool
|
||||
channel chan interface{}
|
||||
closed *gtype.Bool
|
||||
}
|
||||
|
||||
// New creates a graceful channel with given limit.
|
||||
// New creates a graceful channel with given <limit>.
|
||||
func New(limit int) *Chan {
|
||||
return &Chan {
|
||||
channel : make(chan interface{}, limit),
|
||||
closed : gtype.NewBool(),
|
||||
}
|
||||
return &Chan{
|
||||
channel: make(chan interface{}, limit),
|
||||
closed: gtype.NewBool(),
|
||||
}
|
||||
}
|
||||
|
||||
// Push pushes <value> to channel.
|
||||
// It is safe to be called repeatedly.
|
||||
func (c *Chan) Push(value interface{}) error {
|
||||
if c.closed.Val() {
|
||||
return errors.New("closed")
|
||||
}
|
||||
c.channel <- value
|
||||
return nil
|
||||
if c.closed.Val() {
|
||||
return errors.New("channel is closed")
|
||||
}
|
||||
c.channel <- value
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pop pops value from channel.
|
||||
// If there's no value in channel, it would block to wait.
|
||||
// If the channel is closed, it will return a nil value immediately.
|
||||
func (c *Chan) Pop() interface{} {
|
||||
return <- c.channel
|
||||
return <-c.channel
|
||||
}
|
||||
|
||||
// Close closes the channel.
|
||||
// It is safe to be called repeatedly.
|
||||
func (c *Chan) Close() {
|
||||
if !c.closed.Set(true) {
|
||||
close(c.channel)
|
||||
}
|
||||
if !c.closed.Set(true) {
|
||||
close(c.channel)
|
||||
}
|
||||
}
|
||||
|
||||
// See Len.
|
||||
func (c *Chan) Size() int {
|
||||
return c.Len()
|
||||
return c.Len()
|
||||
}
|
||||
|
||||
// Len returns the length of the channel.
|
||||
func (c *Chan) Len() int {
|
||||
return len(c.channel)
|
||||
}
|
||||
}
|
||||
|
||||
// Cap returns the capacity of the channel.
|
||||
func (c *Chan) Cap() int {
|
||||
return cap(c.channel)
|
||||
}
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// go test *.go -bench=".*"
|
||||
|
||||
package gchan_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/gchan"
|
||||
)
|
||||
|
||||
var length = 10000000
|
||||
var q1 = gchan.New(length)
|
||||
var q2 = make(chan int, length)
|
||||
|
||||
func BenchmarkGchanPushAndPop(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
q1.Push(i)
|
||||
q1.Pop()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChannelPushAndPop(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
q2 <- i
|
||||
<- q2
|
||||
}
|
||||
}
|
||||
47
g/container/gchan/gchan_z_unit_test.go
Normal file
47
g/container/gchan/gchan_z_unit_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package gchan_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/container/gchan"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Gchan(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
ch := gchan.New(10)
|
||||
|
||||
gtest.Assert(ch.Cap(), 10)
|
||||
gtest.Assert(ch.Push(1), nil)
|
||||
gtest.Assert(ch.Len(), 1)
|
||||
gtest.Assert(ch.Size(), 1)
|
||||
ch.Pop()
|
||||
gtest.Assert(ch.Len(), 0)
|
||||
gtest.Assert(ch.Size(), 0)
|
||||
ch.Close()
|
||||
gtest.Assert(ch.Push(1), errors.New("channel is closed"))
|
||||
|
||||
ch = gchan.New(0)
|
||||
ch1 := gchan.New(0)
|
||||
go func() {
|
||||
var i = 0
|
||||
for {
|
||||
v := ch.Pop()
|
||||
if v == nil {
|
||||
ch1.Push(i)
|
||||
break
|
||||
}
|
||||
gtest.Assert(v, i)
|
||||
i++
|
||||
}
|
||||
}()
|
||||
|
||||
for index := 0; index < 10; index++ {
|
||||
ch.Push(index)
|
||||
}
|
||||
ch.Close()
|
||||
gtest.Assert(ch1.Pop(), 10)
|
||||
ch1.Close()
|
||||
})
|
||||
}
|
||||
@ -209,6 +209,11 @@ func (l *List) Len() (length int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Size is alias of Len.
|
||||
func (l *List) Size() int {
|
||||
return l.Len()
|
||||
}
|
||||
|
||||
// MoveBefore moves element <e> to its new position before <p>.
|
||||
// If <e> or <p> is not an element of <l>, or <e> == <p>, the list is not modified.
|
||||
// The element and <p> must not be nil.
|
||||
|
||||
@ -7,361 +7,577 @@
|
||||
package glist
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"testing"
|
||||
"container/list"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 检查链表长度
|
||||
func checkListLen(t *testing.T, l *List, len int) bool {
|
||||
if n := l.Len(); n != len {
|
||||
t.Errorf("l.Len() = %d, want %d", n, len)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
if n := l.Len(); n != len {
|
||||
t.Errorf("l.Len() = %d, want %d", n, len)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 检查指针地址
|
||||
func checkListPointers(t *testing.T, l *List, es []*Element) {
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
for i, e := 0, l.list.Front(); i < list.Len(); i, e = i + 1, e.Next() {
|
||||
if e.Prev() != es[i].Prev() {
|
||||
t.Errorf("list[%d].Prev = %p, want %p", i, e.Prev(), es[i].Prev())
|
||||
}
|
||||
if e.Next() != es[i].Next() {
|
||||
t.Errorf("list[%d].Next = %p, want %p", i, e.Next(), es[i].Next())
|
||||
}
|
||||
}
|
||||
})
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
for i, e := 0, l.list.Front(); i < list.Len(); i, e = i+1, e.Next() {
|
||||
if e.Prev() != es[i].Prev() {
|
||||
t.Errorf("list[%d].Prev = %p, want %p", i, e.Prev(), es[i].Prev())
|
||||
}
|
||||
if e.Next() != es[i].Next() {
|
||||
t.Errorf("list[%d].Next = %p, want %p", i, e.Next(), es[i].Next())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestBasic(t *testing.T) {
|
||||
l := New()
|
||||
l.PushFront(1)
|
||||
l.PushFront(2)
|
||||
if v := l.PopBack(); v != 1 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 1, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopBack(); v != 2 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 2, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopBack(); v != nil {
|
||||
t.Errorf("EXPECT %v, GOT %v", nil, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
if v := l.PopFront(); v != 1 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 1, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopFront(); v != 2 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 2, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopFront(); v != nil {
|
||||
t.Errorf("EXPECT %v, GOT %v", nil, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
l := New()
|
||||
l.PushFront(1)
|
||||
l.PushFront(2)
|
||||
if v := l.PopBack(); v != 1 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 1, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopBack(); v != 2 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 2, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopBack(); v != nil {
|
||||
t.Errorf("EXPECT %v, GOT %v", nil, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
if v := l.PopFront(); v != 1 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 1, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopFront(); v != 2 {
|
||||
t.Errorf("EXPECT %v, GOT %v", 2, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
if v := l.PopFront(); v != nil {
|
||||
t.Errorf("EXPECT %v, GOT %v", nil, v)
|
||||
} else {
|
||||
//fmt.Println(v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
l := New()
|
||||
checkListPointers(t, l, []*Element{})
|
||||
l := New()
|
||||
checkListPointers(t, l, []*Element{})
|
||||
|
||||
// Single element list
|
||||
e := l.PushFront("a")
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.MoveToFront(e)
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.MoveToBack(e)
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.Remove(e)
|
||||
checkListPointers(t, l, []*Element{})
|
||||
// Single element list
|
||||
e := l.PushFront("a")
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.MoveToFront(e)
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.MoveToBack(e)
|
||||
checkListPointers(t, l, []*Element{e})
|
||||
l.Remove(e)
|
||||
checkListPointers(t, l, []*Element{})
|
||||
|
||||
// Bigger list
|
||||
e2 := l.PushFront(2)
|
||||
e1 := l.PushFront(1)
|
||||
e3 := l.PushBack(3)
|
||||
e4 := l.PushBack("banana")
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
// Bigger list
|
||||
e2 := l.PushFront(2)
|
||||
e1 := l.PushFront(1)
|
||||
e3 := l.PushBack(3)
|
||||
e4 := l.PushBack("banana")
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
|
||||
l.Remove(e2)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e4})
|
||||
l.Remove(e2)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e4})
|
||||
|
||||
l.MoveToFront(e3) // move from middle
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
l.MoveToFront(e3) // move from middle
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
|
||||
l.MoveToFront(e1)
|
||||
l.MoveToBack(e3) // move from middle
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
l.MoveToFront(e1)
|
||||
l.MoveToBack(e3) // move from middle
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
|
||||
l.MoveToFront(e3) // move from back
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
l.MoveToFront(e3) // should be no-op
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
l.MoveToFront(e3) // move from back
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
l.MoveToFront(e3) // should be no-op
|
||||
checkListPointers(t, l, []*Element{e3, e1, e4})
|
||||
|
||||
l.MoveToBack(e3) // move from front
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
l.MoveToBack(e3) // should be no-op
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
l.MoveToBack(e3) // move from front
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
l.MoveToBack(e3) // should be no-op
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
|
||||
e2 = l.InsertBefore(2, e1) // insert before front
|
||||
checkListPointers(t, l, []*Element{e2, e1, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e4) // insert before middle
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e3) // insert before back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e1) // insert before front
|
||||
checkListPointers(t, l, []*Element{e2, e1, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e4) // insert before middle
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e3) // insert before back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
|
||||
e2 = l.InsertAfter(2, e1) // insert after front
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e4) // insert after middle
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e3) // insert after back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3, e2})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e1) // insert after front
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e4) // insert after middle
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e3) // insert after back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3, e2})
|
||||
l.Remove(e2)
|
||||
|
||||
// Check standard iteration.
|
||||
sum := 0
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
if i, ok := e.Value.(int); ok {
|
||||
sum += i
|
||||
}
|
||||
}
|
||||
if sum != 4 {
|
||||
t.Errorf("sum over l = %d, want 4", sum)
|
||||
}
|
||||
// Check standard iteration.
|
||||
sum := 0
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
if i, ok := e.Value.(int); ok {
|
||||
sum += i
|
||||
}
|
||||
}
|
||||
if sum != 4 {
|
||||
t.Errorf("sum over l = %d, want 4", sum)
|
||||
}
|
||||
|
||||
// Clear all elements by iterating
|
||||
var next *Element
|
||||
for e := l.Front(); e != nil; e = next {
|
||||
next = e.Next()
|
||||
l.Remove(e)
|
||||
}
|
||||
checkListPointers(t, l, []*Element{})
|
||||
// Clear all elements by iterating
|
||||
var next *Element
|
||||
for e := l.Front(); e != nil; e = next {
|
||||
next = e.Next()
|
||||
l.Remove(e)
|
||||
}
|
||||
checkListPointers(t, l, []*Element{})
|
||||
}
|
||||
|
||||
func checkList(t *testing.T, l *List, es []interface{}) {
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
le := e.Value.(int)
|
||||
if le != es[i] {
|
||||
t.Errorf("elt[%d].Value() = %v, want %v", i, le, es[i])
|
||||
}
|
||||
i++
|
||||
}
|
||||
i := 0
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
|
||||
switch e.Value.(type) {
|
||||
case int:
|
||||
if le := e.Value.(int); le != es[i] {
|
||||
t.Errorf("elt[%d].Value() = %v, want %v", i, le, es[i])
|
||||
}
|
||||
// default string
|
||||
default:
|
||||
if le := e.Value.(string); le != es[i] {
|
||||
t.Errorf("elt[%v].Value() = %v, want %v", i, le, es[i])
|
||||
}
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
//for e := l.Front(); e != nil; e = e.Next() {
|
||||
// le := e.Value.(int)
|
||||
// if le != es[i] {
|
||||
// t.Errorf("elt[%d].Value() = %v, want %v", i, le, es[i])
|
||||
// }
|
||||
// i++
|
||||
//}
|
||||
}
|
||||
|
||||
func TestExtending(t *testing.T) {
|
||||
l1 := New()
|
||||
l2 := New()
|
||||
l1 := New()
|
||||
l2 := New()
|
||||
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
l1.PushBack(3)
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
l1.PushBack(3)
|
||||
|
||||
l2.PushBack(4)
|
||||
l2.PushBack(5)
|
||||
l2.PushBack(4)
|
||||
l2.PushBack(5)
|
||||
|
||||
l3 := New()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l2)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
|
||||
l3 := New()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l2)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
|
||||
|
||||
l3 = New()
|
||||
l3.PushFrontList(l2)
|
||||
checkList(t, l3, []interface{}{4, 5})
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
|
||||
l3 = New()
|
||||
l3.PushFrontList(l2)
|
||||
checkList(t, l3, []interface{}{4, 5})
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
|
||||
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
checkList(t, l2, []interface{}{4, 5})
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
checkList(t, l2, []interface{}{4, 5})
|
||||
|
||||
l3 = New()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
l3 = New()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
|
||||
l3 = New()
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushFrontList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
l3 = New()
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushFrontList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
|
||||
l3 = New()
|
||||
l1.PushBackList(l3)
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
l1.PushFrontList(l3)
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
l3 = New()
|
||||
l1.PushBackList(l3)
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
l1.PushFrontList(l3)
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
l := New()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
checkListPointers(t, l, []*Element{e1, e2})
|
||||
//e := l.Front()
|
||||
//l.Remove(e)
|
||||
//checkListPointers(t, l, []*Element{e2})
|
||||
//l.Remove(e)
|
||||
//checkListPointers(t, l, []*Element{e2})
|
||||
l := New()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
checkListPointers(t, l, []*Element{e1, e2})
|
||||
//e := l.Front()
|
||||
//l.Remove(e)
|
||||
//checkListPointers(t, l, []*Element{e2})
|
||||
//l.Remove(e)
|
||||
//checkListPointers(t, l, []*Element{e2})
|
||||
}
|
||||
|
||||
func TestIssue4103(t *testing.T) {
|
||||
l1 := New()
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
l1 := New()
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
|
||||
l2 := New()
|
||||
l2.PushBack(3)
|
||||
l2.PushBack(4)
|
||||
l2 := New()
|
||||
l2.PushBack(3)
|
||||
l2.PushBack(4)
|
||||
|
||||
e := l1.Front()
|
||||
l2.Remove(e) // l2 should not change because e is not an element of l2
|
||||
if n := l2.Len(); n != 2 {
|
||||
t.Errorf("l2.Len() = %d, want 2", n)
|
||||
}
|
||||
e := l1.Front()
|
||||
l2.Remove(e) // l2 should not change because e is not an element of l2
|
||||
if n := l2.Len(); n != 2 {
|
||||
t.Errorf("l2.Len() = %d, want 2", n)
|
||||
}
|
||||
|
||||
l1.InsertBefore(8, e)
|
||||
if n := l1.Len(); n != 3 {
|
||||
t.Errorf("l1.Len() = %d, want 3", n)
|
||||
}
|
||||
l1.InsertBefore(8, e)
|
||||
if n := l1.Len(); n != 3 {
|
||||
t.Errorf("l1.Len() = %d, want 3", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue6349(t *testing.T) {
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
|
||||
e := l.Front()
|
||||
l.Remove(e)
|
||||
if e.Value != 1 {
|
||||
t.Errorf("e.value = %d, want 1", e.Value)
|
||||
}
|
||||
//if e.Next() != nil {
|
||||
// t.Errorf("e.Next() != nil")
|
||||
//}
|
||||
//if e.Prev() != nil {
|
||||
// t.Errorf("e.Prev() != nil")
|
||||
//}
|
||||
e := l.Front()
|
||||
l.Remove(e)
|
||||
if e.Value != 1 {
|
||||
t.Errorf("e.value = %d, want 1", e.Value)
|
||||
}
|
||||
//if e.Next() != nil {
|
||||
// t.Errorf("e.Next() != nil")
|
||||
//}
|
||||
//if e.Prev() != nil {
|
||||
// t.Errorf("e.Prev() != nil")
|
||||
//}
|
||||
}
|
||||
|
||||
func TestMove(t *testing.T) {
|
||||
l := New()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
e3 := l.PushBack(3)
|
||||
e4 := l.PushBack(4)
|
||||
l := New()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
e3 := l.PushBack(3)
|
||||
e4 := l.PushBack(4)
|
||||
|
||||
l.MoveAfter(e3, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e2)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveAfter(e3, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e2)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
|
||||
l.MoveAfter(e3, e2)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveAfter(e3, e2)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e2, e3, e4})
|
||||
|
||||
l.MoveBefore(e2, e4)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
l.MoveBefore(e2, e4)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
|
||||
l.MoveBefore(e4, e1)
|
||||
checkListPointers(t, l, []*Element{e4, e1, e2, e3})
|
||||
e1, e2, e3, e4 = e4, e1, e2, e3
|
||||
l.MoveBefore(e4, e1)
|
||||
checkListPointers(t, l, []*Element{e4, e1, e2, e3})
|
||||
e1, e2, e3, e4 = e4, e1, e2, e3
|
||||
|
||||
l.MoveAfter(e4, e1)
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
e2, e3, e4 = e4, e2, e3
|
||||
l.MoveAfter(e4, e1)
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
e2, e3, e4 = e4, e2, e3
|
||||
|
||||
l.MoveAfter(e2, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
l.MoveAfter(e2, e3)
|
||||
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
}
|
||||
|
||||
// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
|
||||
func TestZeroList(t *testing.T) {
|
||||
var l1 = New()
|
||||
l1.PushFront(1)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
var l1 = New()
|
||||
l1.PushFront(1)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
|
||||
var l2 = New()
|
||||
l2.PushBack(1)
|
||||
checkList(t, l2, []interface{}{1})
|
||||
var l2 = New()
|
||||
l2.PushBack(1)
|
||||
checkList(t, l2, []interface{}{1})
|
||||
|
||||
var l3 = New()
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1})
|
||||
var l3 = New()
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1})
|
||||
|
||||
var l4 = New()
|
||||
l4.PushBackList(l2)
|
||||
checkList(t, l4, []interface{}{1})
|
||||
var l4 = New()
|
||||
l4.PushBackList(l2)
|
||||
checkList(t, l4, []interface{}{1})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
|
||||
func TestInsertBeforeUnknownMark(t *testing.T) {
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertBefore(1, new(Element))
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertBefore(1, new(Element))
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
|
||||
func TestInsertAfterUnknownMark(t *testing.T) {
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertAfter(1, new(Element))
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertAfter(1, new(Element))
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
|
||||
func TestMoveUnknownMark(t *testing.T) {
|
||||
l1 := New()
|
||||
e1 := l1.PushBack(1)
|
||||
l1 := New()
|
||||
e1 := l1.PushBack(1)
|
||||
|
||||
l2 := New()
|
||||
e2 := l2.PushBack(2)
|
||||
l2 := New()
|
||||
e2 := l2.PushBack(2)
|
||||
|
||||
l1.MoveAfter(e1, e2)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
checkList(t, l2, []interface{}{2})
|
||||
l1.MoveAfter(e1, e2)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
checkList(t, l2, []interface{}{2})
|
||||
|
||||
l1.MoveBefore(e1, e2)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
checkList(t, l2, []interface{}{2})
|
||||
l1.MoveBefore(e1, e2)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
checkList(t, l2, []interface{}{2})
|
||||
}
|
||||
|
||||
func TestList_RemoveAll(t *testing.T) {
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.RemoveAll()
|
||||
checkList(t, l, []interface{}{})
|
||||
l.PushBack(2)
|
||||
checkList(t, l, []interface{}{2})
|
||||
}
|
||||
l := New()
|
||||
l.PushBack(1)
|
||||
l.RemoveAll()
|
||||
checkList(t, l, []interface{}{})
|
||||
l.PushBack(2)
|
||||
checkList(t, l, []interface{}{2})
|
||||
}
|
||||
|
||||
func TestList_PushFronts(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2}
|
||||
l.PushFronts(a1)
|
||||
checkList(t, l, []interface{}{2, 1})
|
||||
a1 = []interface{}{3, 4, 5}
|
||||
l.PushFronts(a1)
|
||||
checkList(t, l, []interface{}{5, 4, 3, 2, 1})
|
||||
}
|
||||
|
||||
func TestList_PushBacks(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2}
|
||||
l.PushBacks(a1)
|
||||
checkList(t, l, []interface{}{1, 2})
|
||||
a1 = []interface{}{3, 4, 5}
|
||||
l.PushBacks(a1)
|
||||
checkList(t, l, []interface{}{1, 2, 3, 4, 5})
|
||||
}
|
||||
|
||||
func TestList_PopBacks(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
a2 := []interface{}{"a", "c", "b", "e"}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.PopBacks(2)
|
||||
gtest.Assert(i1, []interface{}{"1", "2"})
|
||||
|
||||
l.PushBacks(a2) //4.3,a,c,b,e
|
||||
i1 = l.PopBacks(3)
|
||||
gtest.Assert(i1, []interface{}{"e", "b", "c"})
|
||||
|
||||
}
|
||||
|
||||
func TestList_PopFronts(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.PopFronts(2)
|
||||
gtest.Assert(i1, []interface{}{"4", "3"})
|
||||
gtest.Assert(l.Len(), 2)
|
||||
}
|
||||
|
||||
func TestList_PopBackAll(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.PopBackAll()
|
||||
gtest.Assert(i1, []interface{}{1, 2, 3, 4})
|
||||
gtest.Assert(l.Len(), 0)
|
||||
|
||||
}
|
||||
|
||||
func TestList_PopFrontAll(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.PopFrontAll()
|
||||
gtest.Assert(i1, []interface{}{4, 3, 2, 1})
|
||||
gtest.Assert(l.Len(), 0)
|
||||
}
|
||||
|
||||
func TestList_FrontAll(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.FrontAll()
|
||||
gtest.Assert(i1, []interface{}{4, 3, 2, 1})
|
||||
gtest.Assert(l.Len(), 4)
|
||||
}
|
||||
|
||||
func TestList_BackAll(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.BackAll()
|
||||
gtest.Assert(i1, []interface{}{1, 2, 3, 4})
|
||||
gtest.Assert(l.Len(), 4)
|
||||
}
|
||||
|
||||
func TestList_FrontValue(t *testing.T) {
|
||||
l := New()
|
||||
l2 := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.FrontValue()
|
||||
gtest.Assert(gconv.Int(i1), 4)
|
||||
gtest.Assert(l.Len(), 4)
|
||||
|
||||
i1 = l2.FrontValue()
|
||||
gtest.Assert(i1, nil)
|
||||
}
|
||||
|
||||
func TestList_BackValue(t *testing.T) {
|
||||
l := New()
|
||||
l2 := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
i1 := l.BackValue()
|
||||
gtest.Assert(gconv.Int(i1), 1)
|
||||
gtest.Assert(l.Len(), 4)
|
||||
|
||||
i1 = l2.FrontValue()
|
||||
gtest.Assert(i1, nil)
|
||||
|
||||
}
|
||||
|
||||
func TestList_Back(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
e1 := l.Back()
|
||||
gtest.Assert(e1.Value, 1)
|
||||
gtest.Assert(l.Len(), 4)
|
||||
}
|
||||
|
||||
func TestList_Size(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
gtest.Assert(l.Size(), 4)
|
||||
l.PopFront()
|
||||
gtest.Assert(l.Size(), 3)
|
||||
}
|
||||
|
||||
func TestList_Removes(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
e1 := l.Back()
|
||||
l.Removes([]*Element{e1})
|
||||
gtest.Assert(l.Len(), 3)
|
||||
|
||||
e2 := l.Back()
|
||||
l.Removes([]*Element{e2})
|
||||
gtest.Assert(l.Len(), 2)
|
||||
checkList(t, l, []interface{}{4, 3})
|
||||
|
||||
}
|
||||
|
||||
func TestList_Clear(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
l.Clear()
|
||||
gtest.Assert(l.Len(), 0)
|
||||
}
|
||||
|
||||
func TestList_IteratorAsc(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 5, 6, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
e1 := l.Back()
|
||||
fun1 := func(e *Element) bool {
|
||||
if gconv.Int(e1.Value) > 2 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
checkList(t, l, []interface{}{4, 3, 6, 5, 2, 1})
|
||||
l.IteratorAsc(fun1)
|
||||
checkList(t, l, []interface{}{4, 3, 6, 5, 2, 1})
|
||||
}
|
||||
|
||||
func TestList_IteratorDesc(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{1, 2, 3, 4}
|
||||
l.PushFronts(a1)
|
||||
e1 := l.Back()
|
||||
fun1 := func(e *Element) bool {
|
||||
if gconv.Int(e1.Value) > 6 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
l.IteratorDesc(fun1)
|
||||
gtest.Assert(l.Len(), 4)
|
||||
checkList(t, l, []interface{}{4, 3, 2, 1})
|
||||
}
|
||||
|
||||
func TestList_Iterator(t *testing.T) {
|
||||
l := New()
|
||||
a1 := []interface{}{"a", "b", "c", "d", "e"}
|
||||
l.PushFronts(a1)
|
||||
e1 := l.Back()
|
||||
fun1 := func(e *Element) bool {
|
||||
if gconv.String(e1.Value) > "c" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
checkList(t, l, []interface{}{"e", "d", "c", "b", "a"})
|
||||
l.Iterator(fun1)
|
||||
checkList(t, l, []interface{}{"e", "d", "c", "b", "a"})
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ type Map = AnyAnyMap
|
||||
type HashMap = AnyAnyMap
|
||||
|
||||
// New returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func New(unsafe ...bool) *Map {
|
||||
return NewAnyAnyMap(unsafe...)
|
||||
@ -21,14 +21,14 @@ func New(unsafe ...bool) *Map {
|
||||
// NewFrom returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewFrom(data map[interface{}]interface{}, unsafe...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, unsafe...)
|
||||
}
|
||||
|
||||
// NewHashMap returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewHashMap(unsafe ...bool) *Map {
|
||||
return NewAnyAnyMap(unsafe...)
|
||||
@ -37,7 +37,7 @@ func NewHashMap(unsafe ...bool) *Map {
|
||||
// NewHashMapFrom returns a hash map from given map <data>.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewHashMapFrom(data map[interface{}]interface{}, unsafe...bool) *Map {
|
||||
return NewAnyAnyMapFrom(data, unsafe...)
|
||||
|
||||
@ -17,7 +17,7 @@ type AnyAnyMap struct {
|
||||
}
|
||||
|
||||
// NewAnyAnyMap returns an empty hash map.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewAnyAnyMap(unsafe ...bool) *AnyAnyMap {
|
||||
return &AnyAnyMap{
|
||||
|
||||
@ -19,7 +19,7 @@ type IntAnyMap struct {
|
||||
}
|
||||
|
||||
// NewIntAnyMap returns an empty IntAnyMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntAnyMap(unsafe...bool) *IntAnyMap {
|
||||
return &IntAnyMap{
|
||||
|
||||
@ -16,7 +16,7 @@ type IntIntMap struct {
|
||||
}
|
||||
|
||||
// NewIntIntMap returns an empty IntIntMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntIntMap(unsafe...bool) *IntIntMap {
|
||||
return &IntIntMap{
|
||||
|
||||
@ -17,7 +17,7 @@ type IntStrMap struct {
|
||||
}
|
||||
|
||||
// NewIntStrMap returns an empty IntStrMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntStrMap(unsafe ...bool) *IntStrMap {
|
||||
return &IntStrMap{
|
||||
|
||||
@ -19,7 +19,7 @@ type StrAnyMap struct {
|
||||
}
|
||||
|
||||
// NewStrAnyMap returns an empty StrAnyMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrAnyMap(unsafe ...bool) *StrAnyMap {
|
||||
return &StrAnyMap{
|
||||
|
||||
@ -18,7 +18,7 @@ type StrIntMap struct {
|
||||
}
|
||||
|
||||
// NewStrIntMap returns an empty StrIntMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrIntMap(unsafe ...bool) *StrIntMap {
|
||||
return &StrIntMap{
|
||||
|
||||
@ -17,7 +17,7 @@ type StrStrMap struct {
|
||||
}
|
||||
|
||||
// NewStrStrMap returns an empty StrStrMap object.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStrStrMap(unsafe...bool) *StrStrMap {
|
||||
return &StrStrMap{
|
||||
|
||||
@ -25,7 +25,7 @@ type gListMapNode struct {
|
||||
|
||||
// NewListMap returns an empty link map.
|
||||
// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
|
||||
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using map in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewListMap(unsafe ...bool) *ListMap {
|
||||
return &ListMap{
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
type TreeMap = gtree.RedBlackTree
|
||||
|
||||
// NewTreeMap instantiates a tree map with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMap(comparator func(v1, v2 interface{}) int, unsafe...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTree(comparator, unsafe...)
|
||||
@ -23,7 +23,7 @@ func NewTreeMap(comparator func(v1, v2 interface{}) int, unsafe...bool) *TreeMap
|
||||
// NewTreeMapFrom instantiates a tree map with the custom comparator and <data> map.
|
||||
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *TreeMap {
|
||||
return gtree.NewRedBlackTreeFrom(comparator, data, unsafe...)
|
||||
|
||||
@ -43,10 +43,11 @@ type ExpireFunc func(interface{})
|
||||
|
||||
// New returns a new object pool.
|
||||
// To ensure execution efficiency, the expiration time cannot be modified once it is set.
|
||||
// Expire:
|
||||
//
|
||||
// Expiration logistics:
|
||||
// expire = 0 : not expired;
|
||||
// expire < 0 : immediate recovery after use;
|
||||
// expire > 0 : timeout recovery;
|
||||
// expire < 0 : immediate expired after use;
|
||||
// expire > 0 : timeout expired;
|
||||
// Note that the expiration time unit is ** milliseconds **.
|
||||
func New(expire int, newFunc NewFunc, expireFunc...ExpireFunc) *Pool {
|
||||
r := &Pool {
|
||||
@ -103,14 +104,26 @@ func (p *Pool) Size() int {
|
||||
return p.list.Len()
|
||||
}
|
||||
|
||||
// Close closes the pool.
|
||||
// Close closes the pool. If <p> has ExpireFunc,
|
||||
// then it automatically closes all items using this function before it's closed.
|
||||
func (p *Pool) Close() {
|
||||
p.closed.Set(true)
|
||||
}
|
||||
|
||||
// checkExpire secondly removes expired items from pool.
|
||||
// checkExpire removes expired items from pool every second.
|
||||
func (p *Pool) checkExpire() {
|
||||
if p.closed.Val() {
|
||||
// If p has ExpireFunc,
|
||||
// then it must close all items using this function.
|
||||
if p.ExpireFunc != nil {
|
||||
for {
|
||||
if r := p.list.PopFront(); r != nil {
|
||||
p.ExpireFunc(r.(*poolItem).value)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
gtimer.Exit()
|
||||
}
|
||||
for {
|
||||
|
||||
@ -6,14 +6,15 @@
|
||||
|
||||
// go test *.go -bench=".*"
|
||||
|
||||
package gpool
|
||||
package gpool_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/gpool"
|
||||
"testing"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var pool = New(99999999, nil)
|
||||
var pool = gpool.New(99999999, nil)
|
||||
var syncp = sync.Pool{}
|
||||
|
||||
func BenchmarkGPoolPut(b *testing.B) {
|
||||
92
g/container/gpool/gpool_z_unit_test.go
Normal file
92
g/container/gpool/gpool_z_unit_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
package gpool_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/gpool"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
var nf gpool.NewFunc = func() (i interface{}, e error) {
|
||||
return "hello", nil
|
||||
}
|
||||
|
||||
var assertIndex int = 0
|
||||
var ef gpool.ExpireFunc = func(i interface{}) {
|
||||
assertIndex++
|
||||
gtest.Assert(i, assertIndex)
|
||||
}
|
||||
|
||||
func Test_Gpool(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire = 0
|
||||
p1 := gpool.New(0, nf)
|
||||
p1.Put(1)
|
||||
p1.Put(2)
|
||||
time.Sleep(1 * time.Second)
|
||||
//test won't be timeout
|
||||
v1, err1 := p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 1)
|
||||
//test clear
|
||||
p1.Clear()
|
||||
gtest.Assert(p1.Size(), 0)
|
||||
//test newFunc
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, "hello")
|
||||
//put data again
|
||||
p1.Put(3)
|
||||
p1.Put(4)
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, 3)
|
||||
//test close
|
||||
p1.Close()
|
||||
v1, err1 = p1.Get()
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(v1, "hello")
|
||||
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire > 0
|
||||
p2 := gpool.New(2000, nil, ef)
|
||||
for index := 0; index < 10; index++ {
|
||||
p2.Put(index)
|
||||
}
|
||||
gtest.Assert(p2.Size(), 10)
|
||||
v2, err2 := p2.Get()
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(v2, 0)
|
||||
//test timeout expireFunc
|
||||
time.Sleep(3 * time.Second)
|
||||
v2, err2 = p2.Get()
|
||||
gtest.Assert(err2, errors.New("pool is empty"))
|
||||
gtest.Assert(v2, nil)
|
||||
//test close expireFunc
|
||||
for index := 0; index < 10; index++ {
|
||||
p2.Put(index)
|
||||
}
|
||||
gtest.Assert(p2.Size(), 10)
|
||||
v2, err2 = p2.Get()
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(v2, 0)
|
||||
assertIndex = 0
|
||||
p2.Close()
|
||||
time.Sleep(3 * time.Second)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
//
|
||||
//expire < 0
|
||||
p3 := gpool.New(-1, nil)
|
||||
v3, err3 := p3.Get()
|
||||
gtest.Assert(err3, errors.New("pool is empty"))
|
||||
gtest.Assert(v3, nil)
|
||||
})
|
||||
}
|
||||
@ -37,8 +37,8 @@ const (
|
||||
)
|
||||
|
||||
// New returns an empty queue object.
|
||||
// Optional parameter <limit> is used to limit the size of the queue, which is unlimited by default.
|
||||
// When <limit> is given, the queue will be static and high performance which is comparable with stdlib chan.
|
||||
// Optional parameter <limit> is used to limit the size of the queue, which is unlimited in default.
|
||||
// When <limit> is given, the queue will be static and high performance which is comparable with stdlib channel.
|
||||
func New(limit...int) *Queue {
|
||||
q := &Queue {
|
||||
closed : make(chan struct{}, 0),
|
||||
@ -103,16 +103,23 @@ func (q *Queue) Pop() interface{} {
|
||||
|
||||
// Close closes the queue.
|
||||
// Notice: It would notify all goroutines return immediately,
|
||||
// which are being blocked reading by Pop method.
|
||||
// which are being blocked reading using Pop method.
|
||||
func (q *Queue) Close() {
|
||||
close(q.C)
|
||||
close(q.events)
|
||||
close(q.closed)
|
||||
}
|
||||
|
||||
// Size returns the length of the queue.
|
||||
func (q *Queue) Size() int {
|
||||
return len(q.C) + q.list.Len()
|
||||
// Len returns the length of the queue.
|
||||
func (q *Queue) Len() (length int) {
|
||||
if q.list != nil {
|
||||
length += q.list.Len()
|
||||
}
|
||||
length += len(q.C)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Size is alias of Len.
|
||||
func (q *Queue) Size() int {
|
||||
return q.Len()
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ type Set struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(unsafe...bool) *Set {
|
||||
return NewSet(unsafe...)
|
||||
|
||||
@ -19,7 +19,7 @@ type IntSet struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewIntSet(unsafe...bool) *IntSet {
|
||||
return &IntSet{
|
||||
|
||||
@ -19,7 +19,7 @@ type StringSet struct {
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewStringSet(unsafe...bool) *StringSet {
|
||||
return &StringSet {
|
||||
|
||||
@ -9,152 +9,208 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIntSet_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(1).Add(2)
|
||||
s.Add([]int{3,4}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN(1, s.Slice())
|
||||
gtest.AssertIN(2, s.Slice())
|
||||
gtest.AssertIN(3, s.Slice())
|
||||
gtest.AssertIN(4, s.Slice())
|
||||
gtest.AssertNI(0, s.Slice())
|
||||
gtest.Assert(s.Contains(4), true)
|
||||
gtest.Assert(s.Contains(5), false)
|
||||
s.Remove(1)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(1).Add(2)
|
||||
s.Add([]int{3, 4}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN(1, s.Slice())
|
||||
gtest.AssertIN(2, s.Slice())
|
||||
gtest.AssertIN(3, s.Slice())
|
||||
gtest.AssertIN(4, s.Slice())
|
||||
gtest.AssertNI(0, s.Slice())
|
||||
gtest.Assert(s.Contains(4), true)
|
||||
gtest.Assert(s.Contains(5), false)
|
||||
s.Remove(1)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Iterator(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v int) bool {
|
||||
a1.Append(1)
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v int) bool {
|
||||
a2.Append(1)
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v int) bool {
|
||||
a1.Append(1)
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v int) bool {
|
||||
a2.Append(1)
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[int]struct{}) {
|
||||
delete(m, 1)
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[int]struct{}) {
|
||||
gtest.Assert(m, map[int]struct{}{
|
||||
3 : struct{}{},
|
||||
2 : struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[int]struct{}) {
|
||||
delete(m, 1)
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[int]struct{}) {
|
||||
gtest.Assert(m, map[int]struct{}{
|
||||
3: struct{}{},
|
||||
2: struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Equal(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s3 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s3 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_IsSubsetOf(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s3 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s3 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Union(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(3).Add(4)
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(3).Add(4)
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Diff(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), false)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), false)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Intersect(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Complement(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
gtest.Assert(s3.Contains(5), true)
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
gtest.Assert(s3.Contains(5), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Size(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet(true)
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s1.Size(), 3)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestIntSet_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s2 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Merge(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(5), true)
|
||||
gtest.Assert(s3.Contains(6), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s3 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(s3, "3"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2 := gset.NewIntSet()
|
||||
s2.Add(5).Add(6).Add(7)
|
||||
gtest.Assert(s2.Sum(), 18)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestIntSet_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add(4).Add(2).Add(3)
|
||||
gtest.AssertIN(s1.Pop(1), []int{4, 2, 3})
|
||||
gtest.AssertIN(s1.Pop(5), []int{4, 2, 3})
|
||||
gtest.Assert(s1.Size(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,152 +9,248 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringSet_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("1").Add("2")
|
||||
s.Add([]string{"3","4"}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN("1", s.Slice())
|
||||
gtest.AssertIN("2", s.Slice())
|
||||
gtest.AssertIN("3", s.Slice())
|
||||
gtest.AssertIN("4", s.Slice())
|
||||
gtest.AssertNI("0", s.Slice())
|
||||
gtest.Assert(s.Contains("4"), true)
|
||||
gtest.Assert(s.Contains("5"), false)
|
||||
s.Remove("1")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("1").Add("2")
|
||||
s.Add([]string{"3", "4"}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN("1", s.Slice())
|
||||
gtest.AssertIN("2", s.Slice())
|
||||
gtest.AssertIN("3", s.Slice())
|
||||
gtest.AssertIN("4", s.Slice())
|
||||
gtest.AssertNI("0", s.Slice())
|
||||
gtest.Assert(s.Contains("4"), true)
|
||||
gtest.Assert(s.Contains("5"), false)
|
||||
s.Remove("1")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Iterator(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("2").Add("3")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("2").Add("3")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v string) bool {
|
||||
a1.Append("1")
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v string) bool {
|
||||
a2.Append("1")
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v string) bool {
|
||||
a1.Append("1")
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v string) bool {
|
||||
a2.Append("1")
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("2").Add("3")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[string]struct{}) {
|
||||
delete(m, "1")
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[string]struct{}) {
|
||||
gtest.Assert(m, map[string]struct{}{
|
||||
"3" : struct{}{},
|
||||
"2" : struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStringSet()
|
||||
s.Add("1").Add("2").Add("3")
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[string]struct{}) {
|
||||
delete(m, "1")
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[string]struct{}) {
|
||||
gtest.Assert(m, map[string]struct{}{
|
||||
"3": struct{}{},
|
||||
"2": struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Equal(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s3 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("1").Add("2").Add("3")
|
||||
s3.Add("1").Add("2").Add("3").Add("4")
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s3 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("1").Add("2").Add("3")
|
||||
s3.Add("1").Add("2").Add("3").Add("4")
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_IsSubsetOf(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s3 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2")
|
||||
s2.Add("1").Add("2").Add("3")
|
||||
s3.Add("1").Add("2").Add("3").Add("4")
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s3 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2")
|
||||
s2.Add("1").Add("2").Add("3")
|
||||
s3.Add("1").Add("2").Add("3").Add("4")
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Union(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2")
|
||||
s2.Add("3").Add("4")
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains("1"), true)
|
||||
gtest.Assert(s3.Contains("2"), true)
|
||||
gtest.Assert(s3.Contains("3"), true)
|
||||
gtest.Assert(s3.Contains("4"), true)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2")
|
||||
s2.Add("3").Add("4")
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains("1"), true)
|
||||
gtest.Assert(s3.Contains("2"), true)
|
||||
gtest.Assert(s3.Contains("3"), true)
|
||||
gtest.Assert(s3.Contains("4"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Diff(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains("1"), true)
|
||||
gtest.Assert(s3.Contains("2"), true)
|
||||
gtest.Assert(s3.Contains("3"), false)
|
||||
gtest.Assert(s3.Contains("4"), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains("1"), true)
|
||||
gtest.Assert(s3.Contains("2"), true)
|
||||
gtest.Assert(s3.Contains("3"), false)
|
||||
gtest.Assert(s3.Contains("4"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Intersect(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains("1"), false)
|
||||
gtest.Assert(s3.Contains("2"), false)
|
||||
gtest.Assert(s3.Contains("3"), true)
|
||||
gtest.Assert(s3.Contains("4"), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains("1"), false)
|
||||
gtest.Assert(s3.Contains("2"), false)
|
||||
gtest.Assert(s3.Contains("3"), true)
|
||||
gtest.Assert(s3.Contains("4"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Complement(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains("1"), false)
|
||||
gtest.Assert(s3.Contains("2"), false)
|
||||
gtest.Assert(s3.Contains("4"), true)
|
||||
gtest.Assert(s3.Contains("5"), true)
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains("1"), false)
|
||||
gtest.Assert(s3.Contains("2"), false)
|
||||
gtest.Assert(s3.Contains("4"), true)
|
||||
gtest.Assert(s3.Contains("5"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewIntSetFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSetFrom([]int{1, 2, 3, 4})
|
||||
s2 := gset.NewIntSetFrom([]int{5, 6, 7, 8})
|
||||
gtest.Assert(s1.Contains(3), true)
|
||||
gtest.Assert(s1.Contains(5), false)
|
||||
gtest.Assert(s2.Contains(3), false)
|
||||
gtest.Assert(s2.Contains(5), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSet()
|
||||
s2 := gset.NewStringSet()
|
||||
s1.Add("1").Add("2").Add("3")
|
||||
s2.Add("3").Add("4").Add("5")
|
||||
s3 := s1.Merge(s2)
|
||||
gtest.Assert(s3.Contains("1"), true)
|
||||
gtest.Assert(s3.Contains("6"), false)
|
||||
gtest.Assert(s3.Contains("4"), true)
|
||||
gtest.Assert(s3.Contains("5"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewStringSetFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
gtest.Assert(s1.Contains("b"), true)
|
||||
gtest.Assert(s1.Contains("d"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Join(t *testing.T) {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, "b"), true)
|
||||
gtest.Assert(strings.Contains(str1, "d"), false)
|
||||
}
|
||||
|
||||
func TestStringSet_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
str1 := s1.String()
|
||||
gtest.Assert(strings.Contains(str1, "b"), true)
|
||||
gtest.Assert(strings.Contains(str1, "d"), false)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestStringSet_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
s2 := gset.NewIntSetFrom([]int{2, 3, 4}, true)
|
||||
gtest.Assert(s1.Sum(), 0)
|
||||
gtest.Assert(s2.Sum(), 9)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Size(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
gtest.Assert(s1.Size(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
s1 = s1.Remove("b")
|
||||
gtest.Assert(s1.Contains("b"), false)
|
||||
gtest.Assert(s1.Contains("c"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
str1 := s1.Pop(1)
|
||||
gtest.Assert(strings.Contains("a,b,c", str1), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStringSet_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStringSetFrom([]string{"a", "b", "c"}, true)
|
||||
strs1 := s1.Pops(2)
|
||||
gtest.AssertIN(strs1, []string{"a", "b", "c"})
|
||||
gtest.Assert(len(strs1), 2)
|
||||
str2 := s1.Pops(7)
|
||||
gtest.AssertIN(str2, []string{"a", "b", "c"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,152 +9,260 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"strings"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSet_New(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.New()
|
||||
s.Add(1).Add(1).Add(2)
|
||||
s.Add([]interface{}{3, 4}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN(1, s.Slice())
|
||||
gtest.AssertIN(2, s.Slice())
|
||||
gtest.AssertIN(3, s.Slice())
|
||||
gtest.AssertIN(4, s.Slice())
|
||||
gtest.AssertNI(0, s.Slice())
|
||||
gtest.Assert(s.Contains(4), true)
|
||||
gtest.Assert(s.Contains(5), false)
|
||||
s.Remove(1)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(1).Add(2)
|
||||
s.Add([]interface{}{3,4}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN(1, s.Slice())
|
||||
gtest.AssertIN(2, s.Slice())
|
||||
gtest.AssertIN(3, s.Slice())
|
||||
gtest.AssertIN(4, s.Slice())
|
||||
gtest.AssertNI(0, s.Slice())
|
||||
gtest.Assert(s.Contains(4), true)
|
||||
gtest.Assert(s.Contains(5), false)
|
||||
s.Remove(1)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(1).Add(2)
|
||||
s.Add([]interface{}{3, 4}...)
|
||||
gtest.Assert(s.Size(), 4)
|
||||
gtest.AssertIN(1, s.Slice())
|
||||
gtest.AssertIN(2, s.Slice())
|
||||
gtest.AssertIN(3, s.Slice())
|
||||
gtest.AssertIN(4, s.Slice())
|
||||
gtest.AssertNI(0, s.Slice())
|
||||
gtest.Assert(s.Contains(4), true)
|
||||
gtest.Assert(s.Contains(5), false)
|
||||
s.Remove(1)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.Clear()
|
||||
gtest.Assert(s.Size(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Iterator(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v interface{}) bool {
|
||||
a1.Append(1)
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v interface{}) bool {
|
||||
a2.Append(1)
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
a1 := garray.New()
|
||||
a2 := garray.New()
|
||||
s.Iterator(func(v interface{}) bool {
|
||||
a1.Append(1)
|
||||
return false
|
||||
})
|
||||
s.Iterator(func(v interface{}) bool {
|
||||
a2.Append(1)
|
||||
return true
|
||||
})
|
||||
gtest.Assert(a1.Len(), 1)
|
||||
gtest.Assert(a2.Len(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[interface{}]struct{}) {
|
||||
delete(m, 1)
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[interface{}]struct{}) {
|
||||
gtest.Assert(m, map[interface{}]struct{}{
|
||||
3 : struct{}{},
|
||||
2 : struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewSet()
|
||||
s.Add(1).Add(2).Add(3)
|
||||
gtest.Assert(s.Size(), 3)
|
||||
s.LockFunc(func(m map[interface{}]struct{}) {
|
||||
delete(m, 1)
|
||||
})
|
||||
gtest.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[interface{}]struct{}) {
|
||||
gtest.Assert(m, map[interface{}]struct{}{
|
||||
3: struct{}{},
|
||||
2: struct{}{},
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Equal(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s3 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s3 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.Equal(s2), true)
|
||||
gtest.Assert(s1.Equal(s3), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_IsSubsetOf(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s3 := gset.NewSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s3 := gset.NewSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(1).Add(2).Add(3)
|
||||
s3.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.IsSubsetOf(s2), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s1.IsSubsetOf(s3), true)
|
||||
gtest.Assert(s2.IsSubsetOf(s1), false)
|
||||
gtest.Assert(s3.IsSubsetOf(s2), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Union(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(3).Add(4)
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2)
|
||||
s2.Add(3).Add(4)
|
||||
s3 := s1.Union(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Diff(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), false)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Diff(s2)
|
||||
gtest.Assert(s3.Contains(1), true)
|
||||
gtest.Assert(s3.Contains(2), true)
|
||||
gtest.Assert(s3.Contains(3), false)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Intersect(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Intersect(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s3.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Complement(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
gtest.Assert(s3.Contains(5), true)
|
||||
})
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewSet()
|
||||
s2 := gset.NewSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s2.Add(3).Add(4).Add(5)
|
||||
s3 := s1.Complement(s2)
|
||||
gtest.Assert(s3.Contains(1), false)
|
||||
gtest.Assert(s3.Contains(2), false)
|
||||
gtest.Assert(s3.Contains(4), true)
|
||||
gtest.Assert(s3.Contains(5), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewFrom("a")
|
||||
s2 := gset.NewFrom("b", false)
|
||||
s3 := gset.NewFrom(3, true)
|
||||
s4 := gset.NewFrom([]string{"s1", "s2"}, true)
|
||||
gtest.Assert(s1.Contains("a"), true)
|
||||
gtest.Assert(s2.Contains("b"), true)
|
||||
gtest.Assert(s3.Contains(3), true)
|
||||
gtest.Assert(s4.Contains("s1"), true)
|
||||
gtest.Assert(s4.Contains("s3"), false)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New()
|
||||
s1.Add("a").Add(2)
|
||||
s2 := gset.New(true)
|
||||
s2.Add("b").Add(3)
|
||||
gtest.Assert(s1.Contains("a"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add("a").Add("a1").Add("b").Add("c")
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, "a1"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add("a").Add("a2").Add("b").Add("c")
|
||||
str1 := s1.String()
|
||||
gtest.Assert(strings.Contains(str1, "a2"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s2 := gset.New(true)
|
||||
s1.Add("a").Add("a2").Add("b").Add("c")
|
||||
s2.Add("b").Add("b1").Add("e").Add("f")
|
||||
ss := s1.Merge(s2)
|
||||
gtest.Assert(ss.Contains("a2"), true)
|
||||
gtest.Assert(ss.Contains("b1"), true)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.Assert(s1.Sum(), int(10))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Pop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.AssertIN(s1.Pop(1), []int{1, 2, 3, 4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Pops(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add(1).Add(2).Add(3).Add(4)
|
||||
gtest.AssertIN(s1.Pops(1), []int{1, 2, 3, 4})
|
||||
gtest.AssertIN(s1.Pops(6), []int{1, 2, 3, 4})
|
||||
gtest.Assert(len(s1.Pops(2)), 2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -29,8 +29,8 @@ type AVLTreeNode struct {
|
||||
b int8
|
||||
}
|
||||
|
||||
// NewAVLTree instantiates an AVL tree with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// NewAVLTree instantiates an AVL tree with the custom key comparator.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree {
|
||||
return &AVLTree{
|
||||
@ -39,8 +39,8 @@ func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree
|
||||
}
|
||||
}
|
||||
|
||||
// NewAVLTreeFrom instantiates an AVL tree with the custom comparator and data map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// NewAVLTreeFrom instantiates an AVL tree with the custom key comparator and data map.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *AVLTree {
|
||||
tree := NewAVLTree(comparator, unsafe...)
|
||||
@ -222,7 +222,7 @@ func (tree *AVLTree) Contains(key interface{}) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// Remove remove the node from the tree by key.
|
||||
// Remove removes the node from the tree by key.
|
||||
// Key should adhere to the comparator's type assertion, otherwise method panics.
|
||||
func (tree *AVLTree) Remove(key interface{}) (value interface{}) {
|
||||
tree.mu.Lock()
|
||||
@ -306,7 +306,7 @@ func (tree *AVLTree) Right() *AVLTreeNode {
|
||||
return node
|
||||
}
|
||||
|
||||
// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found.
|
||||
// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found.
|
||||
// Second return parameter is true if floor was found, otherwise false.
|
||||
//
|
||||
// Floor node is defined as the largest node that is smaller than or equal to the given node.
|
||||
@ -317,16 +317,15 @@ func (tree *AVLTree) Right() *AVLTreeNode {
|
||||
func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
found = false
|
||||
n := tree.root
|
||||
for n != nil {
|
||||
c := tree.comparator(key, n.Key)
|
||||
switch {
|
||||
case c == 0: return n, true
|
||||
case c < 0: n = n.children[0]
|
||||
case c > 0:
|
||||
floor, found = n, true
|
||||
n = n.children[1]
|
||||
case c == 0: return n, true
|
||||
case c < 0: n = n.children[0]
|
||||
case c > 0:
|
||||
floor, found = n, true
|
||||
n = n.children[1]
|
||||
}
|
||||
}
|
||||
if found {
|
||||
@ -335,7 +334,7 @@ func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling is found.
|
||||
// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found.
|
||||
// Second return parameter is true if ceiling was found, otherwise false.
|
||||
//
|
||||
// Ceiling node is defined as the smallest node that is larger than or equal to the given node.
|
||||
@ -343,10 +342,9 @@ func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) {
|
||||
// all nodes in the tree is smaller than the given node.
|
||||
//
|
||||
// Key should adhere to the comparator's type assertion, otherwise method panics.
|
||||
func (tree *AVLTree) Ceiling(key interface{}) (floor *AVLTreeNode, found bool) {
|
||||
func (tree *AVLTree) Ceiling(key interface{}) (ceiling *AVLTreeNode, found bool) {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
found = false
|
||||
n := tree.root
|
||||
for n != nil {
|
||||
c := tree.comparator(key, n.Key)
|
||||
@ -354,7 +352,7 @@ func (tree *AVLTree) Ceiling(key interface{}) (floor *AVLTreeNode, found bool) {
|
||||
case c == 0: return n, true
|
||||
case c > 0: n = n.children[1]
|
||||
case c < 0:
|
||||
floor, found = n, true
|
||||
ceiling, found = n, true
|
||||
n = n.children[0]
|
||||
}
|
||||
}
|
||||
@ -514,7 +512,7 @@ func (tree *AVLTree) remove(key interface{}, qp **AVLTreeNode) (value interface{
|
||||
if fix {
|
||||
return value, removeFix(int8(-c), qp)
|
||||
}
|
||||
return nil, false
|
||||
return value, false
|
||||
}
|
||||
|
||||
func removeMin(qp **AVLTreeNode, minKey *interface{}, minVal *interface{}) bool {
|
||||
|
||||
@ -37,7 +37,7 @@ type BTreeEntry struct {
|
||||
}
|
||||
|
||||
// NewBTree instantiates a B-tree with <m> (maximum number of children) and a custom key comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
// Note that the <m> must be greater or equal than 3, or else it panics.
|
||||
func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BTree {
|
||||
@ -52,7 +52,7 @@ func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BT
|
||||
}
|
||||
|
||||
// NewBTreeFrom instantiates a B-tree with <m> (maximum number of children), a custom key comparator and data map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *BTree {
|
||||
tree := NewBTree(m, comparator, unsafe...)
|
||||
@ -503,9 +503,9 @@ func (tree *BTree) isLeaf(node *BTreeNode) bool {
|
||||
return len(node.Children) == 0
|
||||
}
|
||||
|
||||
func (tree *BTree) isFull(node *BTreeNode) bool {
|
||||
return len(node.Entries) == tree.maxEntries()
|
||||
}
|
||||
//func (tree *BTree) isFull(node *BTreeNode) bool {
|
||||
// return len(node.Entries) == tree.maxEntries()
|
||||
//}
|
||||
|
||||
func (tree *BTree) shouldSplit(node *BTreeNode) bool {
|
||||
return len(node.Entries) > tree.maxEntries()
|
||||
|
||||
@ -36,8 +36,8 @@ type RedBlackTreeNode struct {
|
||||
parent *RedBlackTreeNode
|
||||
}
|
||||
|
||||
// NewRedBlackTree instantiates a red-black tree with the custom comparator.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// NewRedBlackTree instantiates a red-black tree with the custom key comparator.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *RedBlackTree {
|
||||
return &RedBlackTree {
|
||||
@ -46,8 +46,8 @@ func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *Re
|
||||
}
|
||||
}
|
||||
|
||||
// NewRedBlackTreeFrom instantiates a red-black tree with the custom comparator and <data> map.
|
||||
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and <data> map.
|
||||
// The parameter <unsafe> used to specify whether using tree in un-concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *RedBlackTree {
|
||||
tree := NewRedBlackTree(comparator, unsafe...)
|
||||
@ -393,60 +393,56 @@ func (tree *RedBlackTree) rightNode() *RedBlackTreeNode {
|
||||
return p
|
||||
}
|
||||
|
||||
// Floor Finds floor node of the input <key>, return the floor node or nil if no floor is found.
|
||||
// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found.
|
||||
// Second return parameter is true if floor was found, otherwise false.
|
||||
//
|
||||
// Floor node is defined as the largest node that its key is smaller than or equal to the given <key>.
|
||||
// A floor node may not be found, either because the tree is empty, or because
|
||||
// all nodes in the tree are larger than the given node.
|
||||
func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode) {
|
||||
func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode, found bool) {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
found := false
|
||||
node := tree.root
|
||||
for node != nil {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
n := tree.root
|
||||
for n != nil {
|
||||
compare := tree.comparator(key, n.Key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
return node
|
||||
case compare < 0:
|
||||
node = node.left
|
||||
case compare > 0:
|
||||
floor, found = node, true
|
||||
node = node.right
|
||||
case compare == 0: return n, true
|
||||
case compare < 0: n = n.left
|
||||
case compare > 0:
|
||||
floor, found = n, true
|
||||
n = n.right
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return floor
|
||||
return
|
||||
}
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Ceiling finds ceiling node of the input <key>, return the ceiling node or nil if no ceiling is found.
|
||||
// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found.
|
||||
// Second return parameter is true if ceiling was found, otherwise false.
|
||||
//
|
||||
// Ceiling node is defined as the smallest node that its key is larger than or equal to the given <key>.
|
||||
// A ceiling node may not be found, either because the tree is empty, or because
|
||||
// all nodes in the tree are smaller than the given node.
|
||||
func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode) {
|
||||
func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode, found bool) {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
found := false
|
||||
node := tree.root
|
||||
for node != nil {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
n := tree.root
|
||||
for n != nil {
|
||||
compare := tree.comparator(key, n.Key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
return node
|
||||
case compare < 0:
|
||||
ceiling, found = node, true
|
||||
node = node.left
|
||||
case compare > 0:
|
||||
node = node.right
|
||||
case compare == 0: return n, true
|
||||
case compare > 0: n = n.right
|
||||
case compare < 0:
|
||||
ceiling, found = n, true
|
||||
n = n.left
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return ceiling
|
||||
return
|
||||
}
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
|
||||
291
g/container/gtype/gtype_z_unit_test.go
Normal file
291
g/container/gtype/gtype_z_unit_test.go
Normal file
@ -0,0 +1,291 @@
|
||||
package gtype_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
type Temp struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func Test_Bool(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBool(true)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(false), true)
|
||||
gtest.AssertEQ(iClone.Val(), false)
|
||||
|
||||
i1 := gtype.NewBool(false)
|
||||
iClone1 := i1.Clone()
|
||||
gtest.AssertEQ(iClone1.Set(true), false)
|
||||
gtest.AssertEQ(iClone1.Val(), true)
|
||||
|
||||
//空参测试
|
||||
i2 := gtype.NewBool()
|
||||
gtest.AssertEQ(i2.Val(), false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Byte(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 127
|
||||
i := gtype.NewByte(byte(0))
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(byte(1)), byte(0))
|
||||
gtest.AssertEQ(iClone.Val(), byte(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(byte(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewByte()
|
||||
gtest.AssertEQ(i1.Val(), byte(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Bytes(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBytes([]byte("abc"))
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set([]byte("123")), []byte("abc"))
|
||||
gtest.AssertEQ(iClone.Val(), []byte("123"))
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewBytes()
|
||||
gtest.AssertEQ(i1.Val(), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewString("abc")
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set("123"), "abc")
|
||||
gtest.AssertEQ(iClone.Val(), "123")
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewString()
|
||||
gtest.AssertEQ(i1.Val(), "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Interface(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
t := Temp{Name: "gf", Age: 18}
|
||||
t1 := Temp{Name: "gf", Age: 19}
|
||||
i := gtype.New(t)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(t1), t)
|
||||
gtest.AssertEQ(iClone.Val().(Temp), t1)
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.New()
|
||||
gtest.AssertEQ(i1.Val(), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Float32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//var wg sync.WaitGroup
|
||||
//addTimes := 100
|
||||
i := gtype.NewFloat32(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(0.1), float32(0))
|
||||
gtest.AssertEQ(iClone.Val(), float32(0.1))
|
||||
// for index := 0; index < addTimes; index++ {
|
||||
// wg.Add(1)
|
||||
// go func() {
|
||||
// defer wg.Done()
|
||||
// i.Add(0.2)
|
||||
// fmt.Println(i.Val())
|
||||
// }()
|
||||
// }
|
||||
// wg.Wait()
|
||||
// gtest.AssertEQ(100.0, i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewFloat32()
|
||||
gtest.AssertEQ(i1.Val(), float32(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Float64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//var wg sync.WaitGroup
|
||||
//addTimes := 100
|
||||
i := gtype.NewFloat64(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(0.1), float64(0))
|
||||
gtest.AssertEQ(iClone.Val(), float64(0.1))
|
||||
// for index := 0; index < addTimes; index++ {
|
||||
// wg.Add(1)
|
||||
// go func() {
|
||||
// defer wg.Done()
|
||||
// i.Add(0.1)
|
||||
// fmt.Println(i.Val())
|
||||
// }()
|
||||
// }
|
||||
// wg.Wait()
|
||||
// gtest.AssertEQ(100.0, i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewFloat64()
|
||||
gtest.AssertEQ(i1.Val(), float64(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewInt(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), 0)
|
||||
gtest.AssertEQ(iClone.Val(), 1)
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(addTimes, i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewInt()
|
||||
gtest.AssertEQ(i1.Val(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewInt32(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), int32(0))
|
||||
gtest.AssertEQ(iClone.Val(), int32(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(int32(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewInt32()
|
||||
gtest.AssertEQ(i1.Val(), int32(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewInt64(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), int64(0))
|
||||
gtest.AssertEQ(iClone.Val(), int64(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(int64(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewInt64()
|
||||
gtest.AssertEQ(i1.Val(), int64(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewUint(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), uint(0))
|
||||
gtest.AssertEQ(iClone.Val(), uint(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(uint(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewUint()
|
||||
gtest.AssertEQ(i1.Val(), uint(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint32(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewUint32(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), uint32(0))
|
||||
gtest.AssertEQ(iClone.Val(), uint32(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(uint32(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewUint32()
|
||||
gtest.AssertEQ(i1.Val(), uint32(0))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint64(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var wg sync.WaitGroup
|
||||
addTimes := 1000
|
||||
i := gtype.NewUint64(0)
|
||||
iClone := i.Clone()
|
||||
gtest.AssertEQ(iClone.Set(1), uint64(0))
|
||||
gtest.AssertEQ(iClone.Val(), uint64(1))
|
||||
for index := 0; index < addTimes; index++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
i.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
gtest.AssertEQ(uint64(addTimes), i.Val())
|
||||
|
||||
//空参测试
|
||||
i1 := gtype.NewUint64()
|
||||
gtest.AssertEQ(i1.Val(), uint64(0))
|
||||
})
|
||||
}
|
||||
@ -20,7 +20,7 @@ type Var struct {
|
||||
}
|
||||
|
||||
// New returns a new Var with given <value>.
|
||||
// The param <unsafe> used to specify whether using Var in un-concurrent-safety,
|
||||
// The parameter <unsafe> used to specify whether using Var in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func New(value interface{}, unsafe...bool) *Var {
|
||||
v := &Var{}
|
||||
@ -59,7 +59,7 @@ func (v *Var) Interface() interface{} {
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The param <format> specifies the format of the time string using gtime,
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
@ -72,17 +72,17 @@ func (v *Var) Duration() time.Duration {
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The param <format> specifies the format of the time string using gtime,
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <objPointer>.
|
||||
// The param <objPointer> should be a pointer to a struct instance.
|
||||
// The param <attrMapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(objPointer interface{}, attrMapping...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), objPointer, attrMapping...)
|
||||
// The parameter <objPointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
func (v *Var) IsNil() bool { return v.Val() == nil }
|
||||
|
||||
@ -25,18 +25,18 @@ func Encrypt(plainText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
plainText = PKCS5Padding(plainText, blockSize)
|
||||
ivValue := ([]byte)(nil)
|
||||
plainText = PKCS5Padding(plainText, blockSize)
|
||||
ivValue := ([]byte)(nil)
|
||||
if len(iv) > 0 {
|
||||
ivValue = iv[0]
|
||||
} else {
|
||||
ivValue = []byte(ivDefValue)
|
||||
}
|
||||
blockMode := cipher.NewCBCEncrypter(block, ivValue)
|
||||
ciphertext := make([]byte, len(plainText))
|
||||
blockMode.CryptBlocks(ciphertext, plainText)
|
||||
cipherText := make([]byte, len(plainText))
|
||||
blockMode.CryptBlocks(cipherText, plainText)
|
||||
|
||||
return ciphertext, nil
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// AES解密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数
|
||||
@ -65,7 +65,6 @@ func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
package gaes_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/crypto/gaes"
|
||||
@ -16,52 +17,111 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
content = []byte("pibigstar")
|
||||
content = []byte("pibigstar")
|
||||
content_16, _ = gbase64.Decode("v1jqsGHId/H8onlVHR8Vaw==")
|
||||
content_24, _ = gbase64.Decode("0TXOaj5KMoLhNWmJ3lxY1A==")
|
||||
content_32, _ = gbase64.Decode("qM/Waw1kkWhrwzek24rCSA==")
|
||||
content_16_iv, _ = gbase64.Decode("DqQUXiHgW/XFb6Qs98+hrA==")
|
||||
content_32_iv, _ = gbase64.Decode("ZuLgAOii+lrD5KJoQ7yQ8Q==")
|
||||
// iv 长度必须等于blockSize,只能为16
|
||||
iv = []byte("Hello My GoFrame")
|
||||
key_16 = []byte("1234567891234567")
|
||||
key_24 = []byte("123456789123456789123456")
|
||||
key_32 = []byte("12345678912345678912345678912345")
|
||||
keys = []byte("12345678912345678912345678912346")
|
||||
iv = []byte("Hello My GoFrame")
|
||||
key_16 = []byte("1234567891234567")
|
||||
key_17 = []byte("12345678912345670")
|
||||
key_24 = []byte("123456789123456789123456")
|
||||
key_32 = []byte("12345678912345678912345678912345")
|
||||
keys = []byte("12345678912345678912345678912346")
|
||||
key_err = []byte("1234")
|
||||
key_32_err = []byte("1234567891234567891234567891234 ")
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
_, err := gaes.Encrypt(content, key_16)
|
||||
data, err := gaes.Encrypt(content, key_16)
|
||||
gtest.Assert(err, nil)
|
||||
_, err = gaes.Encrypt(content, key_24)
|
||||
gtest.Assert(data, []byte(content_16))
|
||||
data, err = gaes.Encrypt(content, key_24)
|
||||
gtest.Assert(err, nil)
|
||||
_, err = gaes.Encrypt(content, key_32)
|
||||
gtest.Assert(data, []byte(content_24))
|
||||
data, err = gaes.Encrypt(content, key_32)
|
||||
gtest.Assert(err, nil)
|
||||
_, err = gaes.Encrypt(content, key_16, iv)
|
||||
gtest.Assert(data, []byte(content_32))
|
||||
data, err = gaes.Encrypt(content, key_16, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(data, []byte(content_16_iv))
|
||||
data, err = gaes.Encrypt(content, key_32, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(data, []byte(content_32_iv))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
encrypt, err := gaes.Encrypt(content, key_16)
|
||||
decrypt, err := gaes.Decrypt(encrypt, key_16)
|
||||
decrypt, err := gaes.Decrypt([]byte(content_16), key_16)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(decrypt), string(content))
|
||||
gtest.Assert(decrypt, content)
|
||||
|
||||
encrypt, err = gaes.Encrypt(content, key_24)
|
||||
decrypt, err = gaes.Decrypt(encrypt, key_24)
|
||||
decrypt, err = gaes.Decrypt([]byte(content_24), key_24)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(decrypt), string(content))
|
||||
gtest.Assert(decrypt, content)
|
||||
|
||||
encrypt, err = gaes.Encrypt(content, key_32)
|
||||
decrypt, err = gaes.Decrypt(encrypt, key_32)
|
||||
decrypt, err = gaes.Decrypt([]byte(content_32), key_32)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(decrypt), string(content))
|
||||
gtest.Assert(decrypt, content)
|
||||
|
||||
encrypt, err = gaes.Encrypt(content, key_32, iv)
|
||||
decrypt, err = gaes.Decrypt(encrypt, key_32, iv)
|
||||
decrypt, err = gaes.Decrypt([]byte(content_16_iv), key_16, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(decrypt), string(content))
|
||||
gtest.Assert(decrypt, content)
|
||||
|
||||
encrypt, err = gaes.Encrypt(content, key_32, iv)
|
||||
decrypt, err = gaes.Decrypt(encrypt, keys, iv)
|
||||
decrypt, err = gaes.Decrypt([]byte(content_32_iv), key_32, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(decrypt, content)
|
||||
|
||||
decrypt, err = gaes.Decrypt([]byte(content_32_iv), keys, iv)
|
||||
gtest.Assert(err, "invalid padding")
|
||||
})
|
||||
}
|
||||
|
||||
func TestEncryptErr(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
// encrypt key error
|
||||
_, err := gaes.Encrypt(content, key_err)
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDecryptErr(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
// decrypt key error
|
||||
encrypt, err := gaes.Encrypt(content, key_16)
|
||||
_, err = gaes.Decrypt(encrypt, key_err)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
// decrypt content too short error
|
||||
_, err = gaes.Decrypt([]byte("test"), key_16)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
// decrypt content size error
|
||||
_, err = gaes.Decrypt(key_17, key_16)
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPKCS5UnPaddingErr(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
// PKCS5UnPadding blockSize zero
|
||||
_, err := gaes.PKCS5UnPadding(content, 0)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
// PKCS5UnPadding src len zero
|
||||
_, err = gaes.PKCS5UnPadding([]byte(""), 16)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
// PKCS5UnPadding src len > blockSize
|
||||
_, err = gaes.PKCS5UnPadding(key_17, 16)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
// PKCS5UnPadding src len > blockSize
|
||||
_, err = gaes.PKCS5UnPadding(key_32_err, 32)
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,17 +4,26 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gcrc32 provides useful API for CRC32 encryption/decryption algorithms.
|
||||
// Package gcrc32 provides useful API for CRC32 encryption algorithms.
|
||||
package gcrc32
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// Encrypt encrypts any type of variable using CRC32 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) uint32 {
|
||||
return crc32.ChecksumIEEE(gconv.Bytes(v))
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func EncryptString(v string) uint32 {
|
||||
return crc32.ChecksumIEEE([]byte(v))
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func EncryptBytes(v []byte) uint32 {
|
||||
return crc32.ChecksumIEEE(v)
|
||||
}
|
||||
|
||||
@ -9,13 +9,14 @@
|
||||
package gcrc32_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/crypto/gmd5"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/crypto/gcrc32"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
func TestEncryptString(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := "pibigstar"
|
||||
result := 693191136
|
||||
@ -25,3 +26,19 @@ func TestEncrypt(t *testing.T) {
|
||||
gtest.AssertEQ(int(encrypt2), result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := "pibigstar"
|
||||
result := 693191136
|
||||
encrypt1 := gcrc32.Encrypt(s)
|
||||
encrypt2 := gcrc32.Encrypt([]byte(s))
|
||||
gtest.AssertEQ(int(encrypt1), result)
|
||||
gtest.AssertEQ(int(encrypt2), result)
|
||||
|
||||
strmd5 := gmd5.Encrypt(s)
|
||||
test1 := gcrc32.Encrypt(strmd5)
|
||||
test2 := gcrc32.Encrypt([]byte(strmd5))
|
||||
gtest.AssertEQ(test2, test1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// @author: wenzi1<liyz23@qq.com>
|
||||
//
|
||||
// @author wenzi1<liyz23@qq.com>
|
||||
|
||||
// Package gdes provides useful API for DES encryption/decryption algorithms.
|
||||
package gdes
|
||||
@ -16,11 +17,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
NOPADDING = iota
|
||||
NOPADDING = iota
|
||||
PKCS5PADDING
|
||||
)
|
||||
|
||||
//ECB模式DES加密
|
||||
// ECB模式DES加密
|
||||
func DesECBEncrypt(key []byte, clearText []byte, padding int) ([]byte, error) {
|
||||
text, err := Padding(clearText, padding)
|
||||
if err != nil {
|
||||
@ -42,7 +43,7 @@ func DesECBEncrypt(key []byte, clearText []byte, padding int) ([]byte, error) {
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//ECB模式DES解密
|
||||
// ECB模式DES解密
|
||||
func DesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
text := make([]byte, len(cipherText))
|
||||
block, err := des.NewCipher(key)
|
||||
@ -63,7 +64,7 @@ func DesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//ECB模式3DES加密,密钥长度可以是16或24位长
|
||||
// ECB模式3DES加密,密钥长度可以是16或24位长
|
||||
func TripleDesECBEncrypt(key []byte, clearText []byte, padding int) ( []byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length error")
|
||||
@ -96,7 +97,7 @@ func TripleDesECBEncrypt(key []byte, clearText []byte, padding int) ( []byte, er
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//ECB模式3DES解密,密钥长度可以是16或24位长
|
||||
// ECB模式3DES解密,密钥长度可以是16或24位长
|
||||
func TripleDesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length error")
|
||||
@ -129,7 +130,7 @@ func TripleDesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, e
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//CBC模式DES加密
|
||||
// CBC模式DES加密
|
||||
func DesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
@ -152,7 +153,7 @@ func DesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//CBC模式DES解密
|
||||
// CBC模式DES解密
|
||||
func DesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
@ -175,7 +176,7 @@ func DesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ([]byt
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//CBC模式3DES加密
|
||||
// CBC模式3DES加密
|
||||
func TripleDesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length invalid")
|
||||
@ -210,7 +211,7 @@ func TripleDesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) (
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//CBC模式3DES解密
|
||||
// CBC模式3DES解密
|
||||
func TripleDesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ( []byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length invalid")
|
||||
@ -245,21 +246,21 @@ func TripleDesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int)
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//PKCS5补位
|
||||
// PKCS5补位
|
||||
func PKCS5Padding(text []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(text) % blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(text, padtext...)
|
||||
}
|
||||
|
||||
//去除PKCS5补位
|
||||
// 去除PKCS5补位
|
||||
func PKCS5Unpadding(text []byte) []byte{
|
||||
length := len(text)
|
||||
padtext := int(text[length - 1])
|
||||
return text[:(length - padtext)]
|
||||
}
|
||||
|
||||
//补位方法
|
||||
// 补位方法
|
||||
func Padding(text []byte, padding int)([]byte, error) {
|
||||
switch padding {
|
||||
case NOPADDING:
|
||||
@ -275,7 +276,7 @@ func Padding(text []byte, padding int)([]byte, error) {
|
||||
return text, nil
|
||||
}
|
||||
|
||||
//去除补位方法
|
||||
// 去除补位方法
|
||||
func UnPadding(text []byte, padding int)([]byte, error) {
|
||||
switch padding {
|
||||
case NOPADDING:
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gmd5 provides useful API for MD5 encryption/decryption algorithms.
|
||||
// Package gmd5 provides useful API for MD5 encryption algorithms.
|
||||
package gmd5
|
||||
|
||||
import (
|
||||
@ -15,28 +15,31 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 将任意类型的变量进行md5摘要(注意map等非排序变量造成的不同结果)
|
||||
// Encrypt encrypts any type of variable using MD5 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(gconv.Bytes(v)))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// 将字符串进行MD5哈希摘要计算
|
||||
|
||||
// Deprecated.
|
||||
func EncryptString(v string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(v))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
h := md5.New()
|
||||
h.Write([]byte(v))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// 将文件内容进行MD5哈希摘要计算
|
||||
|
||||
// EncryptFile encrypts file content of <path> using MD5 algorithms.
|
||||
func EncryptFile(path string) string {
|
||||
f, e := os.Open(path)
|
||||
if e != nil {
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
h := md5.New()
|
||||
h := md5.New()
|
||||
_, e = io.Copy(h, f)
|
||||
if e != nil {
|
||||
return ""
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gsha1 provides useful API for SHA1 encryption/decryption algorithms.
|
||||
// Package gsha1 provides useful API for SHA1 encryption algorithms.
|
||||
package gsha1
|
||||
|
||||
import (
|
||||
@ -15,20 +15,20 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 将任意类型的变量进行SHA摘要(注意map等非排序变量造成的不同结果)
|
||||
// 内部使用了md5计算,因此效率会稍微差一些,更多情况请使用 EncodeString
|
||||
// Encrypt encrypts any type of variable using SHA1 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) string {
|
||||
r := sha1.Sum(gconv.Bytes(v))
|
||||
return hex.EncodeToString(r[:])
|
||||
}
|
||||
|
||||
// 对字符串行SHA1摘要计算
|
||||
// Deprecated.
|
||||
func EncryptString(s string) string {
|
||||
r := sha1.Sum([]byte(s))
|
||||
return hex.EncodeToString(r[:])
|
||||
r := sha1.Sum([]byte(s))
|
||||
return hex.EncodeToString(r[:])
|
||||
}
|
||||
|
||||
// 对文件内容进行SHA1摘要计算
|
||||
// EncryptFile encrypts file content of <path> using SHA1 algorithms.
|
||||
func EncryptFile(path string) string {
|
||||
f, e := os.Open(path)
|
||||
if e != nil {
|
||||
|
||||
@ -84,6 +84,7 @@ type DB interface {
|
||||
SetDebug(debug bool)
|
||||
SetSchema(schema string)
|
||||
GetQueriedSqls() []*Sql
|
||||
GetLastSql() *Sql
|
||||
PrintQueriedSqls()
|
||||
SetMaxIdleConns(n int)
|
||||
SetMaxOpenConns(n int)
|
||||
@ -161,7 +162,7 @@ var (
|
||||
)
|
||||
|
||||
// New creates ORM DB object with global configurations.
|
||||
// The param <name> specifies the configuration group name,
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
func New(name ...string) (db DB, err error) {
|
||||
group := configs.defaultGroup
|
||||
@ -209,7 +210,7 @@ func New(name ...string) (db DB, err error) {
|
||||
}
|
||||
|
||||
// Instance returns an instance for DB operations.
|
||||
// The param <name> specifies the configuration group name,
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
func Instance(name ...string) (db DB, err error) {
|
||||
group := configs.defaultGroup
|
||||
|
||||
@ -24,6 +24,17 @@ const (
|
||||
gDEFAULT_DEBUG_SQL_LENGTH = 1000 // 默认调试模式下记录的SQL条数
|
||||
)
|
||||
|
||||
// 获取最近一条执行的sql
|
||||
func (bs *dbBase) GetLastSql() *Sql {
|
||||
if bs.sqls == nil {
|
||||
return nil
|
||||
}
|
||||
if v := bs.sqls.Val(); v != nil {
|
||||
return v.(*Sql)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取已经执行的SQL列表(仅在debug=true时有效)
|
||||
func (bs *dbBase) GetQueriedSqls() []*Sql {
|
||||
if bs.sqls == nil {
|
||||
@ -312,7 +323,7 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
return bs.db.doBatchInsert(link, table, data, option, batch...)
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
dataMap = gconv.Map(data)
|
||||
dataMap = structToMap(data)
|
||||
default:
|
||||
return result, errors.New(fmt.Sprint("unsupported data type:", kind))
|
||||
}
|
||||
@ -390,11 +401,11 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
case reflect.Array:
|
||||
listMap = make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
listMap[i] = gconv.Map(rv.Index(i).Interface())
|
||||
listMap[i] = structToMap(rv.Index(i).Interface())
|
||||
}
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
listMap = List{Map(gconv.Map(list))}
|
||||
listMap = List{Map(structToMap(list))}
|
||||
default:
|
||||
return result, errors.New(fmt.Sprint("unsupported list type:", kind))
|
||||
}
|
||||
@ -504,7 +515,7 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
var fields []string
|
||||
for k, v := range gconv.Map(data) {
|
||||
for k, v := range structToMap(data) {
|
||||
fields = append(fields, fmt.Sprintf("%s%s%s=?", charL, k, charR))
|
||||
params = append(params, convertParam(v))
|
||||
}
|
||||
|
||||
@ -7,19 +7,24 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Type assert api for String().
|
||||
type apiString interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// 格式化SQL查询条件
|
||||
func formatCondition(where interface{}, args []interface{}) (newWhere string, newArgs []interface{}) {
|
||||
// 条件字符串处理
|
||||
@ -36,7 +41,7 @@ func formatCondition(where interface{}, args []interface{}) (newWhere string, ne
|
||||
// map/struct类型
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
for key, value := range gconv.Map(where) {
|
||||
for key, value := range structToMap(where) {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(" AND ")
|
||||
}
|
||||
@ -137,10 +142,19 @@ func convertParam(value interface{}) interface{} {
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
// 底层数据库引擎支持 time.Time 类型
|
||||
if _, ok := value.(time.Time); ok {
|
||||
// 底层数据库引擎支持 time.Time/*time.Time 类型
|
||||
if v, ok := value.(time.Time); ok {
|
||||
if v.IsZero() {
|
||||
return "null"
|
||||
}
|
||||
return value
|
||||
}
|
||||
if v, ok := value.(*time.Time); ok {
|
||||
if v.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
return gconv.String(value)
|
||||
}
|
||||
return value
|
||||
@ -165,12 +179,12 @@ func printSql(v *Sql) {
|
||||
// 格式化错误信息
|
||||
func formatError(err error, query string, args ...interface{}) error {
|
||||
if err != nil {
|
||||
errstr := fmt.Sprintf("DB ERROR: %s\n", err.Error())
|
||||
errstr += fmt.Sprintf("DB QUERY: %s\n", query)
|
||||
errStr := fmt.Sprintf("DB ERROR: %s\n", err.Error())
|
||||
errStr += fmt.Sprintf("DB QUERY: %s\n", query)
|
||||
if len(args) > 0 {
|
||||
errstr += fmt.Sprintf("DB PARAM: %v\n", args)
|
||||
errStr += fmt.Sprintf("DB PARAM: %v\n", args)
|
||||
}
|
||||
err = errors.New(errstr)
|
||||
err = errors.New(errStr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -187,3 +201,42 @@ func getInsertOperationByOption(option int) string {
|
||||
}
|
||||
return operator
|
||||
}
|
||||
|
||||
// 将对象转换为map,如果对象带有继承对象,那么执行递归转换。
|
||||
// 该方法用于将变量传递给数据库执行之前。
|
||||
func structToMap(obj interface{}) map[string]interface{} {
|
||||
data := gconv.Map(obj)
|
||||
for key, value := range data {
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
// 底层数据库引擎支持 time.Time/*time.Time 类型
|
||||
if _, ok := value.(time.Time); ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := value.(*time.Time); ok {
|
||||
continue
|
||||
}
|
||||
// 如果执行String方法,那么执行字符串转换
|
||||
if s, ok := value.(apiString); ok {
|
||||
data[key] = s.String()
|
||||
continue
|
||||
}
|
||||
delete(data, key)
|
||||
for k, v := range structToMap(value) {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 使用递归的方式将map键值对映射到struct对象上,注意参数<pointer>是一个指向struct的指针。
|
||||
func mapToStruct(data map[string]interface{}, pointer interface{}) error {
|
||||
return gconv.StructDeep(data, pointer)
|
||||
}
|
||||
@ -268,12 +268,12 @@ func (md *Model) Data(data ...interface{}) *Model {
|
||||
case reflect.Array:
|
||||
list := make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
list[i] = gconv.Map(rv.Index(i).Interface())
|
||||
list[i] = structToMap(rv.Index(i).Interface())
|
||||
}
|
||||
model.data = list
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
model.data = Map(gconv.Map(data[0]))
|
||||
model.data = Map(structToMap(data[0]))
|
||||
default:
|
||||
model.data = data[0]
|
||||
}
|
||||
|
||||
@ -67,13 +67,13 @@ func (db *dbMssql) parseSql(sql string) string {
|
||||
//下面的正则表达式匹配出SELECT和INSERT的关键字后分别做不同的处理,如有LIMIT则将LIMIT的关键字也匹配出
|
||||
patten := `^\s*(?i)(SELECT)|(LIMIT\s*(\d+)\s*,\s*(\d+))`
|
||||
if gregex.IsMatchString(patten, sql) == false {
|
||||
fmt.Println("not matched..")
|
||||
//fmt.Println("not matched..")
|
||||
return sql
|
||||
}
|
||||
|
||||
res, err := gregex.MatchAllString(patten, sql)
|
||||
if err != nil {
|
||||
fmt.Println("MatchString error.", err)
|
||||
//fmt.Println("MatchString error.", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -83,69 +83,69 @@ func (db *dbMssql) parseSql(sql string) string {
|
||||
|
||||
index++
|
||||
switch keyword {
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
|
||||
//不含LIMIT则不处理
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
|
||||
//判断SQL中是否含有order by
|
||||
selectStr := ""
|
||||
orderbyStr := ""
|
||||
haveOrderby := gregex.IsMatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
if haveOrderby {
|
||||
//取order by 前面的字符串
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "ORDER BY") == false {
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
selectStr = queryExpr[2]
|
||||
|
||||
//取order by表达式的值
|
||||
orderbyExpr, _ := gregex.MatchString("((?i)ORDER BY)(.+)((?i)LIMIT)", sql)
|
||||
if len(orderbyExpr) != 4 || strings.EqualFold(orderbyExpr[1], "ORDER BY") == false || strings.EqualFold(orderbyExpr[3], "LIMIT") == false {
|
||||
//不含LIMIT则不处理
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
orderbyStr = orderbyExpr[2]
|
||||
} else {
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql)
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
selectStr = queryExpr[2]
|
||||
}
|
||||
|
||||
//取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
continue
|
||||
}
|
||||
//判断SQL中是否含有order by
|
||||
selectStr := ""
|
||||
orderbyStr := ""
|
||||
haveOrderby := gregex.IsMatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
if haveOrderby {
|
||||
//取order by 前面的字符串
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
|
||||
if strings.HasPrefix(res[index][i], "LIMIT") || strings.HasPrefix(res[index][i], "limit") {
|
||||
first, _ = strconv.Atoi(res[index][i+1])
|
||||
limit, _ = strconv.Atoi(res[index][i+2])
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "ORDER BY") == false {
|
||||
break
|
||||
}
|
||||
selectStr = queryExpr[2]
|
||||
|
||||
if haveOrderby {
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY %s) as ROWNUMBER_, %s ) as TMP_ WHERE TMP_.ROWNUMBER_ > %d AND TMP_.ROWNUMBER_ <= %d", orderbyStr, selectStr, first, limit)
|
||||
} else {
|
||||
if first == 0 {
|
||||
first = limit
|
||||
//取order by表达式的值
|
||||
orderbyExpr, _ := gregex.MatchString("((?i)ORDER BY)(.+)((?i)LIMIT)", sql)
|
||||
if len(orderbyExpr) != 4 || strings.EqualFold(orderbyExpr[1], "ORDER BY") == false || strings.EqualFold(orderbyExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
orderbyStr = orderbyExpr[2]
|
||||
} else {
|
||||
first = limit - first
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql)
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
selectStr = queryExpr[2]
|
||||
}
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT TOP %d * FROM (SELECT TOP %d %s) as TMP1_ ) as TMP2_ ", first, limit, selectStr)
|
||||
}
|
||||
default:
|
||||
|
||||
//取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(res[index][i], "LIMIT") || strings.HasPrefix(res[index][i], "limit") {
|
||||
first, _ = strconv.Atoi(res[index][i+1])
|
||||
limit, _ = strconv.Atoi(res[index][i+2])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if haveOrderby {
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY %s) as ROWNUMBER_, %s ) as TMP_ WHERE TMP_.ROWNUMBER_ > %d AND TMP_.ROWNUMBER_ <= %d", orderbyStr, selectStr, first, limit)
|
||||
} else {
|
||||
if first == 0 {
|
||||
first = limit
|
||||
} else {
|
||||
first = limit - first
|
||||
}
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT TOP %d * FROM (SELECT TOP %d %s) as TMP1_ ) as TMP2_ ", first, limit, selectStr)
|
||||
}
|
||||
default:
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
@ -65,80 +65,80 @@ func (db *dbOracle) parseSql(sql string) string {
|
||||
//下面的正则表达式匹配出SELECT和INSERT的关键字后分别做不同的处理,如有LIMIT则将LIMIT的关键字也匹配出
|
||||
patten := `^\s*(?i)(SELECT)|(INSERT)|(LIMIT\s*(\d+)\s*,\s*(\d+))`
|
||||
if gregex.IsMatchString(patten, sql) == false {
|
||||
fmt.Println("not matched..")
|
||||
//fmt.Println("not matched..")
|
||||
return sql
|
||||
}
|
||||
|
||||
res, err := gregex.MatchAllString(patten, sql)
|
||||
if err != nil {
|
||||
fmt.Println("MatchString error.", err)
|
||||
//fmt.Println("MatchString error.", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
index := 0
|
||||
index := 0
|
||||
keyword := strings.TrimSpace(res[index][0])
|
||||
keyword = strings.ToUpper(keyword)
|
||||
keyword = strings.ToUpper(keyword)
|
||||
|
||||
index++
|
||||
switch keyword {
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
|
||||
//取limit前面的字符串
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql)
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
|
||||
//取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(res[index][i], "LIMIT") || strings.HasPrefix(res[index][i], "limit") {
|
||||
first, _ = strconv.Atoi(res[index][i+1])
|
||||
limit, _ = strconv.Atoi(res[index][i+2])
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//也可以使用between,据说这种写法的性能会比between好点,里层SQL中的ROWNUM_ >= limit可以缩小查询后的数据集规模
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT GFORM.*, ROWNUM ROWNUM_ FROM (%s %s) GFORM WHERE ROWNUM <= %d) WHERE ROWNUM_ >= %d", queryExpr[1], queryExpr[2], limit, first)
|
||||
case "INSERT":
|
||||
//获取VALUE的值,匹配所有带括号的值,会将INSERT INTO后的值匹配到,所以下面的判断语句会判断数组长度是否小于3
|
||||
valueExpr, err := gregex.MatchAllString(`(\s*\(([^\(\)]*)\))`, sql)
|
||||
if err != nil {
|
||||
return sql
|
||||
}
|
||||
//取limit前面的字符串
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
|
||||
//判断VALUE后的值是否有多个,只有在批量插入的时候才需要做转换,如只有1个VALUE则不需要做转换
|
||||
if len(valueExpr) < 3 {
|
||||
break
|
||||
}
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql)
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
|
||||
//获取INTO后面的值
|
||||
tableExpr, err := gregex.MatchString(`(?i)\s*(INTO\s+\w+\(([^\(\)]*)\))`, sql)
|
||||
if err != nil {
|
||||
return sql
|
||||
}
|
||||
tableExpr[0] = strings.TrimSpace(tableExpr[0])
|
||||
//取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sql = "INSERT ALL"
|
||||
for i := 1; i < len(valueExpr); i++ {
|
||||
sql += fmt.Sprintf(" %s VALUES%s", tableExpr[0], strings.TrimSpace(valueExpr[i][0]))
|
||||
}
|
||||
sql += " SELECT 1 FROM DUAL"
|
||||
if strings.HasPrefix(res[index][i], "LIMIT") || strings.HasPrefix(res[index][i], "limit") {
|
||||
first, _ = strconv.Atoi(res[index][i+1])
|
||||
limit, _ = strconv.Atoi(res[index][i+2])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
//也可以使用between,据说这种写法的性能会比between好点,里层SQL中的ROWNUM_ >= limit可以缩小查询后的数据集规模
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT GFORM.*, ROWNUM ROWNUM_ FROM (%s %s) GFORM WHERE ROWNUM <= %d) WHERE ROWNUM_ >= %d", queryExpr[1], queryExpr[2], limit, first)
|
||||
case "INSERT":
|
||||
//获取VALUE的值,匹配所有带括号的值,会将INSERT INTO后的值匹配到,所以下面的判断语句会判断数组长度是否小于3
|
||||
valueExpr, err := gregex.MatchAllString(`(\s*\(([^\(\)]*)\))`, sql)
|
||||
if err != nil {
|
||||
return sql
|
||||
}
|
||||
|
||||
//判断VALUE后的值是否有多个,只有在批量插入的时候才需要做转换,如只有1个VALUE则不需要做转换
|
||||
if len(valueExpr) < 3 {
|
||||
break
|
||||
}
|
||||
|
||||
//获取INTO后面的值
|
||||
tableExpr, err := gregex.MatchString(`(?i)\s*(INTO\s+\w+\(([^\(\)]*)\))`, sql)
|
||||
if err != nil {
|
||||
return sql
|
||||
}
|
||||
tableExpr[0] = strings.TrimSpace(tableExpr[0])
|
||||
|
||||
sql = "INSERT ALL"
|
||||
for i := 1; i < len(valueExpr); i++ {
|
||||
sql += fmt.Sprintf(" %s VALUES%s", tableExpr[0], strings.TrimSpace(valueExpr[i][0]))
|
||||
}
|
||||
sql += " SELECT 1 FROM DUAL"
|
||||
|
||||
default:
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
@ -28,42 +28,42 @@ func (bs *dbBase) convertValue(fieldValue interface{}, fieldType string) interfa
|
||||
t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
|
||||
t = strings.ToLower(t)
|
||||
switch t {
|
||||
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
|
||||
return gconv.Bytes(fieldValue)
|
||||
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
|
||||
return gconv.Bytes(fieldValue)
|
||||
|
||||
case "bit", "int", "tinyint", "small_int", "medium_int":
|
||||
return gconv.Int(fieldValue)
|
||||
case "bit", "int", "tinyint", "small_int", "medium_int":
|
||||
return gconv.Int(fieldValue)
|
||||
|
||||
case "big_int":
|
||||
return gconv.Int64(fieldValue)
|
||||
case "big_int":
|
||||
return gconv.Int64(fieldValue)
|
||||
|
||||
case "float", "double", "decimal":
|
||||
return gconv.Float64(fieldValue)
|
||||
case "float", "double", "decimal":
|
||||
return gconv.Float64(fieldValue)
|
||||
|
||||
case "bool":
|
||||
return gconv.Bool(fieldValue)
|
||||
case "bool":
|
||||
return gconv.Bool(fieldValue)
|
||||
|
||||
default:
|
||||
// 自动识别类型, 以便默认支持更多数据库类型
|
||||
switch {
|
||||
case strings.Contains(t, "int"):
|
||||
return gconv.Int(fieldValue)
|
||||
default:
|
||||
// 自动识别类型, 以便默认支持更多数据库类型
|
||||
switch {
|
||||
case strings.Contains(t, "int"):
|
||||
return gconv.Int(fieldValue)
|
||||
|
||||
case strings.Contains(t, "text") || strings.Contains(t, "char"):
|
||||
return gconv.String(fieldValue)
|
||||
case strings.Contains(t, "text") || strings.Contains(t, "char"):
|
||||
return gconv.String(fieldValue)
|
||||
|
||||
case strings.Contains(t, "float") || strings.Contains(t, "double"):
|
||||
return gconv.Float64(fieldValue)
|
||||
case strings.Contains(t, "float") || strings.Contains(t, "double"):
|
||||
return gconv.Float64(fieldValue)
|
||||
|
||||
case strings.Contains(t, "bool"):
|
||||
return gconv.Bool(fieldValue)
|
||||
case strings.Contains(t, "bool"):
|
||||
return gconv.Bool(fieldValue)
|
||||
|
||||
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
||||
return gconv.Bytes(fieldValue)
|
||||
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
||||
return gconv.Bytes(fieldValue)
|
||||
|
||||
default:
|
||||
return gconv.String(fieldValue)
|
||||
}
|
||||
default:
|
||||
return gconv.String(fieldValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,7 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
)
|
||||
|
||||
// 将记录结果转换为JSON字符串
|
||||
@ -33,6 +32,6 @@ func (r Record) ToMap() Map {
|
||||
}
|
||||
|
||||
// 将Map变量映射到指定的struct对象中,注意参数应当是一个对象的指针
|
||||
func (r Record) ToStruct(objPointer interface{}) error {
|
||||
return gconv.Struct(r.ToMap(), objPointer)
|
||||
func (r Record) ToStruct(pointer interface{}) error {
|
||||
return mapToStruct(r.ToMap(), pointer)
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDbBase_Ping(t *testing.T) {
|
||||
@ -488,3 +489,51 @@ func TestDbBase_Delete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDbBase_Time(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Insert("user", g.Map{
|
||||
"id" : 200,
|
||||
"passport" : "t200",
|
||||
"password" : "123456",
|
||||
"nickname" : "T200",
|
||||
"create_time" : time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
value, err := db.GetValue("select `passport` from `user` where id=?", 200)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "t200")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
t := time.Now()
|
||||
result, err := db.Insert("user", g.Map{
|
||||
"id" : 300,
|
||||
"passport" : "t300",
|
||||
"password" : "123456",
|
||||
"nickname" : "T300",
|
||||
"create_time" : &t,
|
||||
})
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
value, err := db.GetValue("select `passport` from `user` where id=?", 300)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "t300")
|
||||
})
|
||||
|
||||
if result, err := db.Delete("user", nil); err != nil {
|
||||
gtest.Fatal(err)
|
||||
} else {
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 基本测试
|
||||
|
||||
99
g/database/gdb/gdb_unit_struct_inherit_test.go
Normal file
99
g/database/gdb/gdb_unit_struct_inherit_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestModel_Inherit_Insert(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type Base struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `json:"passport"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
result, err := db.Table("user").Filter().Data(User{
|
||||
Passport : "john-test",
|
||||
Password : "123456",
|
||||
Nickname : "John",
|
||||
Base : Base {
|
||||
Id : 100,
|
||||
Uid : 100,
|
||||
CreateTime : gtime.Now().String(),
|
||||
},
|
||||
}).Insert()
|
||||
gtest.Assert(err, nil)
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
value, err := db.Table("user").Fields("passport").Where("id=100").Value()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "john-test")
|
||||
// Delete this test data.
|
||||
_, err = db.Table("user").Where("id", 100).Delete()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestModel_Inherit_MapToStruct(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type Ids struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `json:"passport"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
data := g.Map{
|
||||
"id" : 100,
|
||||
"uid" : 101,
|
||||
"passport" : "t1",
|
||||
"password" : "123456",
|
||||
"nickname" : "T1",
|
||||
"create_time" : gtime.Now().String(),
|
||||
}
|
||||
result, err := db.Table("user").Filter().Data(data).Insert()
|
||||
gtest.Assert(err, nil)
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
|
||||
one, err := db.Table("user").Where("id=100").One()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
|
||||
gtest.Assert(one.ToStruct(user), nil)
|
||||
gtest.Assert(user.Id, data["id"])
|
||||
gtest.Assert(user.Passport, data["passport"])
|
||||
gtest.Assert(user.Password, data["password"])
|
||||
gtest.Assert(user.Nickname, data["nickname"])
|
||||
gtest.Assert(user.CreateTime, data["create_time"])
|
||||
|
||||
// Delete this test data.
|
||||
_, err = db.Table("user").Where("id", 100).Delete()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -7,133 +7,203 @@
|
||||
package gredis_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"time"
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
redis2 "github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
config = gredis.Config{
|
||||
Host : "127.0.0.1",
|
||||
Port : 6379,
|
||||
Db : 1,
|
||||
}
|
||||
config = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func Test_NewClose(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Do(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Send(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Stats(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500*time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500*time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500 * time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500 * time.Millisecond)
|
||||
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Conn(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
config1 := gredis.Config{
|
||||
Host: "127.0.0.2",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
redis := gredis.New(config1)
|
||||
_, err := redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
Pass: "666666",
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 100,
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
redis = gredis.Instance("gf")
|
||||
gtest.Assert(redis == nil, true)
|
||||
gredis.ClearConfig()
|
||||
|
||||
redis = gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err = redis.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
v, err := redis.DoVar("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v.String(), "v")
|
||||
|
||||
conn := redis.GetConn()
|
||||
_, err = conn.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
//v, err = conn.ReceiveVar()
|
||||
//gtest.Assert(err, nil)
|
||||
//gtest.Assert(v.String(), "v")
|
||||
|
||||
psc := redis2.PubSubConn{Conn: conn}
|
||||
psc.Subscribe("gf")
|
||||
redis.DoVar("PUBLISH", "gf", "gf test")
|
||||
go func() {
|
||||
for {
|
||||
v, _ := conn.ReceiveVar()
|
||||
switch obj := v.Val().(type) {
|
||||
case redis2.Message:
|
||||
gtest.Assert(string(obj.Data), "gf test")
|
||||
case redis2.Subscription:
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,55 +1,110 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright 2018-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// @author wenzi1
|
||||
// @date 20180604
|
||||
|
||||
// Package gcharset provides converting string to requested character encoding.
|
||||
// Package charset implements character-set conversion functionality.
|
||||
//
|
||||
// 字符集转换方法,
|
||||
// 使用mahonia实现的字符集转换方法,支持的字符集包括常见的utf8/UTF-16/UTF-16LE/macintosh/big5/gbk/gb18030,支持的全量字符集可以参考mahonia包
|
||||
// Supported Character Set:
|
||||
//
|
||||
// Chinese : GBK/GB18030/GB2312/Big5
|
||||
//
|
||||
// Japanese: EUCJP/ISO2022JP/ShiftJIS
|
||||
//
|
||||
// Korean : EUCKR
|
||||
//
|
||||
// Unicode : UTF-8/UTF-16/UTF-16BE/UTF-16LE
|
||||
//
|
||||
// Other : macintosh/IBM*/Windows*/ISO-*
|
||||
package gcharset
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/third/github.com/axgle/mahonia"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/encoding"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/encoding/ianaindex"
|
||||
"github.com/gogf/gf/third/golang.org/x/text/transform"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var (
|
||||
// Alias for charsets.
|
||||
charsetAlias = map[string]string {
|
||||
"HZGB2312" : "HZ-GB-2312",
|
||||
"hzgb2312" : "HZ-GB-2312",
|
||||
"GB2312" : "HZ-GB-2312",
|
||||
"gb2312" : "HZ-GB-2312",
|
||||
}
|
||||
)
|
||||
|
||||
// 2个字符集之间的转换
|
||||
// Supported returns whether charset <charset> is supported.
|
||||
func Supported(charset string) bool {
|
||||
return getEncoding(charset) != nil
|
||||
}
|
||||
|
||||
// Convert converts <src> charset encoding from <srcCharset> to <dstCharset>,
|
||||
// and returns the converted string.
|
||||
// It returns <src> as <dst> if it fails converting.
|
||||
func Convert(dstCharset string, srcCharset string, src string) (dst string, err error) {
|
||||
s := mahonia.GetCharset(srcCharset)
|
||||
if s == nil {
|
||||
return "", errors.New(fmt.Sprintf("not support charset:%s", srcCharset))
|
||||
if dstCharset == srcCharset {
|
||||
return src, nil
|
||||
}
|
||||
|
||||
d := mahonia.GetCharset(dstCharset)
|
||||
if d == nil {
|
||||
return "", errors.New(fmt.Sprintf("not support charset:%s", dstCharset))
|
||||
dst = src
|
||||
// Converting <src> to UTF-8.
|
||||
if srcCharset != "UTF-8" {
|
||||
if e := getEncoding(srcCharset); e != nil {
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader([]byte(src)), e.NewDecoder()),
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s to utf8 failed. %v", srcCharset, err)
|
||||
}
|
||||
src = string(tmp)
|
||||
} else {
|
||||
return dst, errors.New(fmt.Sprintf("unsupport srcCharset: %s", srcCharset))
|
||||
}
|
||||
}
|
||||
|
||||
srctmp := src
|
||||
if s.Name != "UTF-8" {
|
||||
srctmp = s.NewDecoder().ConvertString(srctmp)
|
||||
// Do the converting from UTF-8 to <dstCharset>.
|
||||
if dstCharset != "UTF-8" {
|
||||
if e := getEncoding(dstCharset); e != nil {
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader([]byte(src)), e.NewEncoder()),
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("utf to %s failed. %v", dstCharset, err)
|
||||
}
|
||||
dst = string(tmp)
|
||||
} else {
|
||||
return dst, errors.New(fmt.Sprintf("unsupport dstCharset: %s", dstCharset))
|
||||
}
|
||||
} else {
|
||||
dst = src
|
||||
}
|
||||
|
||||
dst = srctmp
|
||||
if d.Name != "UTF-8" {
|
||||
dst = d.NewEncoder().ConvertString(dst)
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// 指定字符集转UTF8
|
||||
func ToUTF8(charset string, src string) (dst string, err error) {
|
||||
return Convert("UTF-8", charset, src)
|
||||
// ToUTF8 converts <src> charset encoding from <srcCharset> to UTF-8 ,
|
||||
// and returns the converted string.
|
||||
func ToUTF8(srcCharset string, src string) (dst string, err error) {
|
||||
return Convert("UTF-8", srcCharset, src)
|
||||
}
|
||||
|
||||
// UTF8转指定字符集
|
||||
func UTF8To(charset string, src string) (dst string, err error) {
|
||||
return Convert(charset, "UTF-8", src)
|
||||
// UTF8To converts <src> charset encoding from UTF-8 to <dstCharset>,
|
||||
// and returns the converted string.
|
||||
func UTF8To(dstCharset string, src string) (dst string, err error) {
|
||||
return Convert(dstCharset, "UTF-8", src)
|
||||
}
|
||||
|
||||
// getEncoding returns the encoding.Encoding interface object for <charset>.
|
||||
// It returns nil if <charset> is not supported.
|
||||
func getEncoding(charset string) encoding.Encoding {
|
||||
if c, ok := charsetAlias[charset]; ok {
|
||||
charset = c
|
||||
}
|
||||
if e, err := ianaindex.MIB.Encoding(charset); err == nil && e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -8,22 +8,23 @@ package gcharset_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gcharset"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testData = []struct {
|
||||
utf8, other, otherEncoding string
|
||||
}{
|
||||
{"Résumé", "Résumé", "utf8"},
|
||||
{"Résumé", "R\xe9sum\xe9", "latin-1"},
|
||||
{"Résumé", "Résumé", "utf-8"},
|
||||
//{"Résumé", "R\xe9sum\xe9", "latin-1"},
|
||||
{"これは漢字です。", "S0\x8c0o0\"oW[g0Y0\x020", "UTF-16LE"},
|
||||
{"これは漢字です。", "0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16BE"},
|
||||
{"これは漢字です。", "\xfe\xff0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16"},
|
||||
{"𝄢𝄞𝄪𝄫", "\xfe\xff\xd8\x34\xdd\x22\xd8\x34\xdd\x1e\xd8\x34\xdd\x2a\xd8\x34\xdd\x2b", "UTF-16"},
|
||||
{"Hello, world", "Hello, world", "ASCII"},
|
||||
//{"Hello, world", "Hello, world", "ASCII"},
|
||||
{"Gdańsk", "Gda\xf1sk", "ISO-8859-2"},
|
||||
{"Ââ Čč Đđ Ŋŋ Õõ Šš Žž Åå Ää", "\xc2\xe2 \xc8\xe8 \xa9\xb9 \xaf\xbf \xd5\xf5 \xaa\xba \xac\xbc \xc5\xe5 \xc4\xe4", "ISO-8859-10"},
|
||||
{"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"},
|
||||
//{"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"},
|
||||
{"latviešu", "latvie\xf0u", "ISO-8859-13"},
|
||||
{"Seònaid", "Se\xf2naid", "ISO-8859-14"},
|
||||
{"€1 is cheap", "\xa41 is cheap", "ISO-8859-15"},
|
||||
@ -49,9 +50,12 @@ var testData = []struct {
|
||||
{"Hello 常用國字標準字體表", "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed", "big5"},
|
||||
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"},
|
||||
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"},
|
||||
{"花间一壶酒,独酌无相亲。", "~{;(<dR;:x>F#,6@WCN^O`GW!#", "GB2312"},
|
||||
{"花间一壶酒,独酌无相亲。", "~{;(<dR;:x>F#,6@WCN^O`GW!#", "HZGB2312"},
|
||||
{"עִבְרִית", "\x81\x30\xfb\x30\x81\x30\xf6\x34\x81\x30\xf9\x33\x81\x30\xf6\x30\x81\x30\xfb\x36\x81\x30\xf6\x34\x81\x30\xfa\x31\x81\x30\xfb\x38", "gb18030"},
|
||||
{"㧯", "\x82\x31\x89\x38", "gb18030"},
|
||||
{"これは漢字です。", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"},
|
||||
{"㧯", "㧯", "UTF-8"},
|
||||
//{"これは漢字です。", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"},
|
||||
{"これは漢字です。", "\xa4\xb3\xa4\xec\xa4\u03f4\xc1\xbb\xfa\xa4\u01e4\xb9\xa1\xa3", "EUC-JP"},
|
||||
}
|
||||
|
||||
@ -63,14 +67,43 @@ func TestDecode(t *testing.T) {
|
||||
t.Errorf("Could not create decoder for %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if str != data.utf8 {
|
||||
t.Errorf("Unexpected value: %#v (expected %#v) %v", str, data.utf8, data.otherEncoding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTF8To(t *testing.T) {
|
||||
for _, data := range testData {
|
||||
str := ""
|
||||
str, err := gcharset.UTF8To(data.otherEncoding, data.utf8)
|
||||
if err != nil {
|
||||
t.Errorf("Could not create decoder for %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if str != data.other {
|
||||
t.Errorf("Unexpected value: %#v (expected %#v) %v", str, data.other, data.otherEncoding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUTF8(t *testing.T) {
|
||||
for _, data := range testData {
|
||||
str := ""
|
||||
str, err := gcharset.ToUTF8(data.otherEncoding, data.other)
|
||||
if err != nil {
|
||||
t.Errorf("Could not create decoder for %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if str != data.utf8 {
|
||||
t.Errorf("Unexpected value: %#v (expected %#v)", str, data.utf8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, data := range testData {
|
||||
str := ""
|
||||
@ -101,4 +134,32 @@ func TestConvert(t *testing.T) {
|
||||
if str != dst {
|
||||
t.Errorf("unexpected value:%#v (expected %#v)", str, dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertErr(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
srcCharset := "big5"
|
||||
dstCharset := "gbk"
|
||||
src := "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed"
|
||||
|
||||
s1, e1 := gcharset.Convert(srcCharset, srcCharset, src)
|
||||
gtest.Assert(e1, nil)
|
||||
gtest.Assert(s1, src)
|
||||
|
||||
|
||||
s2, e2 := gcharset.Convert(dstCharset, "no this charset", src)
|
||||
gtest.AssertNE(e2, nil)
|
||||
gtest.Assert(s2, src)
|
||||
|
||||
s3, e3 := gcharset.Convert("no this charset", srcCharset, src)
|
||||
gtest.AssertNE(e3, nil)
|
||||
gtest.Assert(s3, src)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSupported(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gcharset.Supported("UTF-8"), true)
|
||||
gtest.Assert(gcharset.Supported("UTF-80"), false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gcompress provides kinds of compression algorithms for binary/bytes data.
|
||||
//
|
||||
// 数据压缩/解压.
|
||||
package gcompress
|
||||
|
||||
import (
|
||||
@ -16,19 +14,19 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// 进行zlib压缩
|
||||
// Zlib compresses <data> with zlib algorithm.
|
||||
func Zlib(data []byte) []byte {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data
|
||||
}
|
||||
var in bytes.Buffer
|
||||
w := zlib.NewWriter(&in)
|
||||
w.Write(data)
|
||||
w.Close()
|
||||
w := zlib.NewWriter(&in)
|
||||
_, _ = w.Write(data)
|
||||
_ = w.Close()
|
||||
return in.Bytes()
|
||||
}
|
||||
|
||||
// 进行zlib解压缩
|
||||
// UnZlib decompresses <data> with zlib algorithm.
|
||||
func UnZlib(data []byte) []byte {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data
|
||||
@ -39,32 +37,32 @@ func UnZlib(data []byte) []byte {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
io.Copy(&out, r)
|
||||
_, _ = io.Copy(&out, r)
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
//做gzip解压缩
|
||||
func UnGzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
content := bytes.NewReader(data)
|
||||
zipdata, err := gzip.NewReader(content)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
io.Copy(&buf, zipdata)
|
||||
zipdata.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
//做gzip压缩
|
||||
// Gzip compresses <data> with gzip algorithm.
|
||||
func Gzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
zip := gzip.NewWriter(&buf)
|
||||
var buf bytes.Buffer
|
||||
zip := gzip.NewWriter(&buf)
|
||||
_, err := zip.Write(data)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
zip.Close()
|
||||
|
||||
_ = zip.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
// UnGzip decompresses <data> with gzip algorithm.
|
||||
func UnGzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
content := bytes.NewReader(data)
|
||||
zipData, err := gzip.NewReader(content)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, _ = io.Copy(&buf, zipData)
|
||||
_ = zipData.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gcompress_test
|
||||
|
||||
import (
|
||||
@ -18,6 +19,11 @@ func TestZlib(t *testing.T) {
|
||||
gtest.Assert(gcompress.Zlib([]byte(src)), dst)
|
||||
|
||||
gtest.Assert(gcompress.UnZlib(dst), []byte(src))
|
||||
|
||||
gtest.Assert(gcompress.Zlib(nil), nil)
|
||||
gtest.Assert(gcompress.UnZlib(nil), nil)
|
||||
|
||||
gtest.Assert(gcompress.UnZlib(dst[1:]), nil)
|
||||
})
|
||||
|
||||
}
|
||||
@ -36,7 +42,10 @@ func TestGzip(t *testing.T) {
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
gtest.Assert(gcompress.Gzip([]byte(src)), gzip)
|
||||
arr := []byte(src)
|
||||
gtest.Assert(gcompress.Gzip(arr), gzip)
|
||||
|
||||
gtest.Assert(gcompress.UnGzip(gzip), []byte(src))
|
||||
gtest.Assert(gcompress.UnGzip(gzip), arr)
|
||||
|
||||
gtest.Assert(gcompress.UnGzip(gzip[1:]), nil)
|
||||
}
|
||||
|
||||
@ -5,15 +5,13 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package ghash provides some popular hash functions(uint32/uint64) in go.
|
||||
//
|
||||
// 常用的hash函数.
|
||||
package ghash
|
||||
|
||||
|
||||
// BKDR Hash Function
|
||||
func BKDRHash(str []byte) uint32 {
|
||||
var seed uint32 = 131; // 31 131 1313 13131 131313 etc..
|
||||
var hash uint32 = 0;
|
||||
var seed uint32 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * seed + uint32(str[i])
|
||||
}
|
||||
@ -22,8 +20,8 @@ func BKDRHash(str []byte) uint32 {
|
||||
|
||||
// BKDR Hash Function 64
|
||||
func BKDRHash64(str []byte) uint64 {
|
||||
var seed uint64 = 131; // 31 131 1313 13131 131313 etc..
|
||||
var hash uint64 = 0;
|
||||
var seed uint64 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * seed + uint64(str[i])
|
||||
}
|
||||
@ -32,78 +30,78 @@ func BKDRHash64(str []byte) uint64 {
|
||||
|
||||
// SDBM Hash
|
||||
func SDBMHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i]);
|
||||
hash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash;
|
||||
hash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// SDBM Hash 64
|
||||
func SDBMHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i]);
|
||||
hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash;
|
||||
// equivalent to: hash = 65599*hash + uint32(str[i])
|
||||
hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function
|
||||
func RSHash(str []byte) uint32 {
|
||||
var b uint32 = 378551;
|
||||
var a uint32 = 63689;
|
||||
var hash uint32 = 0;
|
||||
var b uint32 = 378551
|
||||
var a uint32 = 63689
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * a + uint32(str[i]);
|
||||
a *= b;
|
||||
hash = hash * a + uint32(str[i])
|
||||
a *= b
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function 64
|
||||
func RSHash64(str []byte) uint64 {
|
||||
var b uint64 = 378551;
|
||||
var a uint64 = 63689;
|
||||
var hash uint64 = 0;
|
||||
var b uint64 = 378551
|
||||
var a uint64 = 63689
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = hash * a + uint64(str[i]);
|
||||
a *= b;
|
||||
hash = hash * a + uint64(str[i])
|
||||
a *= b;
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function
|
||||
func JSHash(str []byte) uint32 {
|
||||
var hash uint32 = 1315423911;
|
||||
var hash uint32 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash ^= ((hash << 5) + uint32(str[i]) + (hash >> 2));
|
||||
hash ^= (hash << 5) + uint32(str[i]) + (hash >> 2)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function 64
|
||||
func JSHash64(str []byte) uint64 {
|
||||
var hash uint64 = 1315423911;
|
||||
var hash uint64 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash ^= ((hash << 5) + uint64(str[i]) + (hash >> 2));
|
||||
hash ^= (hash << 5) + uint64(str[i]) + (hash >> 2)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// P. J. Weinberger Hash Function
|
||||
func PJWHash(str []byte) uint32 {
|
||||
var BitsInUnignedInt uint32 = (4 * 8);
|
||||
var ThreeQuarters uint32 = ((BitsInUnignedInt * 3) / 4);
|
||||
var OneEighth uint32 = (BitsInUnignedInt / 8);
|
||||
var HighBits uint32 = (0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
|
||||
var hash uint32 = 0;
|
||||
var test uint32 = 0;
|
||||
var BitsInUnignedInt uint32 = 4 * 8
|
||||
var ThreeQuarters uint32 = (BitsInUnignedInt * 3) / 4
|
||||
var OneEighth uint32 = BitsInUnignedInt / 8
|
||||
var HighBits uint32 = (0xFFFFFFFF) << (BitsInUnignedInt - OneEighth)
|
||||
var hash uint32 = 0
|
||||
var test uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << OneEighth) + uint32(str[i]);
|
||||
hash = (hash << OneEighth) + uint32(str[i])
|
||||
if test = hash & HighBits; test != 0 {
|
||||
hash = ((hash ^ (test >> ThreeQuarters)) & (^HighBits + 1));
|
||||
hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -111,16 +109,16 @@ func PJWHash(str []byte) uint32 {
|
||||
|
||||
// P. J. Weinberger Hash Function 64
|
||||
func PJWHash64(str []byte) uint64 {
|
||||
var BitsInUnignedInt uint64 = (4 * 8);
|
||||
var ThreeQuarters uint64 = ((BitsInUnignedInt * 3) / 4);
|
||||
var OneEighth uint64 = (BitsInUnignedInt / 8);
|
||||
var HighBits uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnignedInt - OneEighth);
|
||||
var hash uint64 = 0;
|
||||
var test uint64 = 0;
|
||||
var BitsInUnignedInt uint64 = 4 * 8
|
||||
var ThreeQuarters uint64 = (BitsInUnignedInt * 3) / 4
|
||||
var OneEighth uint64 = BitsInUnignedInt / 8
|
||||
var HighBits uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnignedInt - OneEighth)
|
||||
var hash uint64 = 0
|
||||
var test uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << OneEighth) + uint64(str[i]);
|
||||
hash = (hash << OneEighth) + uint64(str[i])
|
||||
if test = hash & HighBits; test != 0 {
|
||||
hash = ((hash ^ (test >> ThreeQuarters)) & (^HighBits + 1));
|
||||
hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -128,13 +126,13 @@ func PJWHash64(str []byte) uint64 {
|
||||
|
||||
// ELF Hash Function
|
||||
func ELFHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var x uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
var x uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << 4) + uint32(str[i]);
|
||||
hash = (hash << 4) + uint32(str[i])
|
||||
if x = hash & 0xF0000000; x != 0 {
|
||||
hash ^= (x >> 24);
|
||||
hash &= ^x + 1;
|
||||
hash ^= x >> 24
|
||||
hash &= ^x + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -142,13 +140,13 @@ func ELFHash(str []byte) uint32 {
|
||||
|
||||
// ELF Hash Function 64
|
||||
func ELFHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var x uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
var x uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash = (hash << 4) + uint64(str[i]);
|
||||
hash = (hash << 4) + uint64(str[i])
|
||||
if x = hash & 0xF000000000000000; x != 0 {
|
||||
hash ^= (x >> 24);
|
||||
hash &= ^x + 1;
|
||||
hash ^= x >> 24
|
||||
hash &= ^x + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -156,30 +154,30 @@ func ELFHash64(str []byte) uint64 {
|
||||
|
||||
// DJB Hash Function
|
||||
func DJBHash(str []byte) uint32 {
|
||||
var hash uint32 = 5381;
|
||||
var hash uint32 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash += (hash << 5) + uint32(str[i]);
|
||||
hash += (hash << 5) + uint32(str[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// DJB Hash Function 64
|
||||
func DJBHash64(str []byte) uint64 {
|
||||
var hash uint64 = 5381;
|
||||
var hash uint64 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
hash += (hash << 5) + uint64(str[i]);
|
||||
hash += (hash << 5) + uint64(str[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// AP Hash Function
|
||||
func APHash(str []byte) uint32 {
|
||||
var hash uint32 = 0;
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
if ((i & 1) == 0) {
|
||||
hash ^= ((hash << 7) ^ uint32(str[i]) ^ (hash >> 3));
|
||||
if (i & 1) == 0 {
|
||||
hash ^= (hash << 7) ^ uint32(str[i]) ^ (hash >> 3)
|
||||
} else {
|
||||
hash ^= (^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1);
|
||||
hash ^= ^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
@ -187,12 +185,12 @@ func APHash(str []byte) uint32 {
|
||||
|
||||
// AP Hash Function 64
|
||||
func APHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0;
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
if ((i & 1) == 0) {
|
||||
hash ^= ((hash << 7) ^ uint64(str[i]) ^ (hash >> 3));
|
||||
if (i & 1) == 0 {
|
||||
hash ^= (hash << 7) ^ uint64(str[i]) ^ (hash >> 3)
|
||||
} else {
|
||||
hash ^= (^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1);
|
||||
hash ^= ^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1
|
||||
}
|
||||
}
|
||||
return hash
|
||||
|
||||
140
g/encoding/ghash/ghash_z_unit_basic_test.go
Executable file
140
g/encoding/ghash/ghash_z_unit_basic_test.go
Executable file
@ -0,0 +1,140 @@
|
||||
package ghash_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/ghash"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
var (
|
||||
strBasic = []byte("This is the test string for hash.")
|
||||
)
|
||||
|
||||
func Test_BKDRHash(t *testing.T) {
|
||||
var x uint32 = 200645773
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.BKDRHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_BKDRHash64(t *testing.T) {
|
||||
var x uint64 = 4214762819217104013
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.BKDRHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SDBMHash(t *testing.T) {
|
||||
var x uint32 = 1069170245
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.SDBMHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SDBMHash64(t *testing.T) {
|
||||
var x uint64 = 9881052176572890693
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.SDBMHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_RSHash(t *testing.T) {
|
||||
var x uint32 = 1944033799
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.RSHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_RSHash64(t *testing.T) {
|
||||
var x uint64 = 13439708950444349959
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.RSHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_JSHash(t *testing.T) {
|
||||
var x uint32 = 498688898
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.JSHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_JSHash64(t *testing.T) {
|
||||
var x uint64 = 13410163655098759877
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.JSHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_PJWHash(t *testing.T) {
|
||||
var x uint32 = 7244206
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.PJWHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_PJWHash64(t *testing.T) {
|
||||
var x uint64 = 31150
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.PJWHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ELFHash(t *testing.T) {
|
||||
var x uint32 = 7244206
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.ELFHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ELFHash64(t *testing.T) {
|
||||
var x uint64 = 31150
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.ELFHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DJBHash(t *testing.T) {
|
||||
var x uint32 = 959862602
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.DJBHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DJBHash64(t *testing.T) {
|
||||
var x uint64 = 2519720351310960458
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.DJBHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_APHash(t *testing.T) {
|
||||
var x uint32 = 3998202516
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.APHash(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_APHash64(t *testing.T) {
|
||||
var x uint64 = 2531023058543352243
|
||||
gtest.Case(t, func() {
|
||||
j := ghash.APHash64(strBasic)
|
||||
gtest.Assert(j, x)
|
||||
})
|
||||
}
|
||||
@ -108,7 +108,11 @@ func (j *Json) setValue(pattern string, value interface{}, removed bool) error {
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
if removed && value == nil {
|
||||
// 删除数据元素
|
||||
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
|
||||
if pparent == nil {
|
||||
*pointer = append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...)
|
||||
} else {
|
||||
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
|
||||
}
|
||||
} else {
|
||||
(*pointer).([]interface{})[valn] = value
|
||||
}
|
||||
|
||||
@ -43,6 +43,10 @@ func New(data interface{}, unsafe...bool) *Json {
|
||||
default:
|
||||
rv := reflect.ValueOf(data)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice: fallthrough
|
||||
case reflect.Array:
|
||||
@ -56,7 +60,7 @@ func New(data interface{}, unsafe...bool) *Json {
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Struct:
|
||||
i := interface{}(nil)
|
||||
i = gconv.Map(data)
|
||||
i = gconv.Map(data, "json")
|
||||
j = &Json {
|
||||
p : &i,
|
||||
c : byte(gDEFAULT_SPLIT_CHAR),
|
||||
@ -132,11 +136,14 @@ func LoadContent(data interface{}, unsafe...bool) (*Json, error) {
|
||||
var err error
|
||||
var result interface{}
|
||||
b := gconv.Bytes(data)
|
||||
t := "json"
|
||||
t := ""
|
||||
if len(b) == 0 {
|
||||
return New(nil, unsafe...), nil
|
||||
}
|
||||
// auto check data type
|
||||
if json.Valid(b) {
|
||||
t = "json"
|
||||
} else if gregex.IsMatch(`^<.+>.*</.+>$`, b) {
|
||||
} else if gregex.IsMatch(`^<.+>[\S\s]+<.+>$`, b) {
|
||||
t = "xml"
|
||||
} else if gregex.IsMatch(`^[\s\t]*\w+\s*:\s*.+`, b) || gregex.IsMatch(`\n[\s\t]*\w+\s*:\s*.+`, b) {
|
||||
t = "yml"
|
||||
|
||||
@ -7,221 +7,221 @@
|
||||
package gjson_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_New(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewUnsafe(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Valid(t *testing.T) {
|
||||
data1 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
data2 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]`)
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gjson.Valid(data1), true)
|
||||
gtest.Assert(gjson.Valid(data2), false)
|
||||
})
|
||||
data1 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
data2 := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]`)
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gjson.Valid(data1), true)
|
||||
gtest.Assert(gjson.Valid(data2), false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gjson.Encode(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gjson.Encode(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Decode(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
v, err := gjson.Decode(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n" : 123456789,
|
||||
"a" : g.Slice{1, 2, 3},
|
||||
"m" : g.Map{
|
||||
"k" : "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var v interface{}
|
||||
err := gjson.DecodeTo(data, &v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n" : 123456789,
|
||||
"a" : g.Slice{1, 2, 3},
|
||||
"m" : g.Map{
|
||||
"k" : "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
v, err := gjson.Decode(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n": 123456789,
|
||||
"a": g.Slice{1, 2, 3},
|
||||
"m": g.Map{
|
||||
"k": "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var v interface{}
|
||||
err := gjson.DecodeTo(data, &v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v, g.Map{
|
||||
"n": 123456789,
|
||||
"a": g.Slice{1, 2, 3},
|
||||
"m": g.Map{
|
||||
"k": "v",
|
||||
},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SplitChar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ViolenceCheck(t *testing.T) {
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetToVar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k" : "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k": "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetMap(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetJson(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
j2 := j.GetJson("m")
|
||||
gtest.AssertNE(j2, nil)
|
||||
gtest.Assert(j2.Get("k"), "v")
|
||||
gtest.Assert(j2.Get("a"), nil)
|
||||
gtest.Assert(j2.Get("n"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
j2 := j.GetJson("m")
|
||||
gtest.AssertNE(j2, nil)
|
||||
gtest.Assert(j2.Get("k"), "v")
|
||||
gtest.Assert(j2.Get("a"), nil)
|
||||
gtest.Assert(j2.Get("n"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetArray(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetString(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetStrings(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetInterfaces(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gjson.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Append(t *testing.T) {
|
||||
@ -236,8 +236,8 @@ func Test_Append(t *testing.T) {
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b" : g.Slice{1},
|
||||
"c" : g.Slice{2},
|
||||
"b": g.Slice{1},
|
||||
"c": g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
@ -282,21 +282,180 @@ func TestJson_Default(t *testing.T) {
|
||||
gtest.AssertEQ(j.GetUint64("no", 100), uint64(100))
|
||||
gtest.AssertEQ(j.GetFloat32("no", 123.456), float32(123.456))
|
||||
gtest.AssertEQ(j.GetFloat64("no", 123.456), float64(123.456))
|
||||
gtest.AssertEQ(j.GetArray("no", g.Slice{1,2,3}), g.Slice{1,2,3})
|
||||
gtest.AssertEQ(j.GetInts("no", g.Slice{1,2,3}), g.SliceInt{1,2,3})
|
||||
gtest.AssertEQ(j.GetFloats("no", g.Slice{1,2,3}), []float64{1,2,3})
|
||||
gtest.AssertEQ(j.GetMap("no", g.Map{"k":"v"}), g.Map{"k":"v"})
|
||||
gtest.AssertEQ(j.GetArray("no", g.Slice{1, 2, 3}), g.Slice{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetInts("no", g.Slice{1, 2, 3}), g.SliceInt{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetFloats("no", g.Slice{1, 2, 3}), []float64{1, 2, 3})
|
||||
gtest.AssertEQ(j.GetMap("no", g.Map{"k": "v"}), g.Map{"k": "v"})
|
||||
gtest.AssertEQ(j.GetVar("no", 123.456).Float64(), float64(123.456))
|
||||
gtest.AssertEQ(j.GetJson("no", g.Map{"k":"v"}).Get("k"), "v")
|
||||
gtest.AssertEQ(j.GetJson("no", g.Map{"k": "v"}).Get("k"), "v")
|
||||
gtest.AssertEQ(j.GetJsons("no", g.Slice{
|
||||
g.Map{"k1":"v1"},
|
||||
g.Map{"k2":"v2"},
|
||||
g.Map{"k3":"v3"},
|
||||
g.Map{"k1": "v1"},
|
||||
g.Map{"k2": "v2"},
|
||||
g.Map{"k3": "v3"},
|
||||
})[0].Get("k1"), "v1")
|
||||
gtest.AssertEQ(j.GetJsonMap("no", g.Map{
|
||||
"m1" : g.Map{"k1":"v1"},
|
||||
"m2" : g.Map{"k2":"v2"},
|
||||
"m1": g.Map{"k1": "v1"},
|
||||
"m2": g.Map{"k2": "v2"},
|
||||
})["m2"].Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(`{"name":"gf"}`)
|
||||
arr, err := j.ToXml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "<name>gf</name>")
|
||||
arr, err = j.ToXmlIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "<name>gf</name>")
|
||||
str, err := j.ToXmlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "<name>gf</name>")
|
||||
str, err = j.ToXmlIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "<name>gf</name>")
|
||||
|
||||
arr, err = j.ToJsonIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "{\n\t\"name\": \"gf\"\n}")
|
||||
str, err = j.ToJsonIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "{\n\t\"name\": \"gf\"\n}")
|
||||
|
||||
arr, err = j.ToYaml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name: gf\n")
|
||||
str, err = j.ToYamlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name: gf\n")
|
||||
|
||||
arr, err = j.ToToml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name = \"gf\"\n")
|
||||
str, err = j.ToTomlString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(string(arr), "name = \"gf\"\n")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert2(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
name := struct {
|
||||
Name string
|
||||
}{}
|
||||
j := gjson.New(`{"name":"gf","time":"2019-06-12"}`)
|
||||
gtest.Assert(j.Value().(g.Map)["name"], "gf")
|
||||
gtest.Assert(j.GetMap("name1"), nil)
|
||||
gtest.Assert(j.GetJson("name1"), nil)
|
||||
gtest.Assert(j.GetJsons("name1"), nil)
|
||||
gtest.Assert(j.GetJsonMap("name1"), nil)
|
||||
gtest.Assert(j.Contains("name1"), false)
|
||||
gtest.Assert(j.GetToVar("name1", &name) == nil, true)
|
||||
gtest.Assert(j.GetToVar("name", &name) == nil, false)
|
||||
gtest.Assert(j.Len("name1"), -1)
|
||||
gtest.Assert(j.GetTime("time").Format("2006-01-02"), "2019-06-12")
|
||||
gtest.Assert(j.GetGTime("time").Format("Y-m-d"), "2019-06-12")
|
||||
gtest.Assert(j.GetDuration("time").String(), "0s")
|
||||
|
||||
err := j.ToStruct(&name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
err = j.Dump()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j = gjson.New(`{"person":{"name":"gf"}}`)
|
||||
err = j.GetToStruct("person", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
|
||||
j = gjson.New(`{"name":"gf""}`)
|
||||
err = j.Dump()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
gtest.Assert(len(j.ToArray()), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(`{"name":"gf","time":"2019-06-12"}`)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
gtest.Assert(j.Get("").(g.Map)["name1"], nil)
|
||||
j.SetViolenceCheck(false)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
|
||||
err := j.Set("name", "gf1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("name"), "gf1")
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("\"0\".1", 11)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("1"), 11)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("11111111111111111111111", 11)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("0"), 1)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("3")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("0"), 1)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.3")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(j.Get("0").([]interface{})), 3)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.a")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(j.Get("0").(g.Map)), 0)
|
||||
|
||||
name := struct {
|
||||
Name string
|
||||
}{Name: "gf"}
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
err = j.Set("Name", "gf1")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), "gf1")
|
||||
|
||||
j = gjson.New(nil)
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Set("Name1", g.Map{"Name": "gf1"})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name1").(g.Map)["Name"], "gf1")
|
||||
err = j.Set("Name2", g.Slice{1, 2, 3})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name2").(g.Slice)[0], 1)
|
||||
err = j.Set("Name3", name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name3").(g.Map)["Name"], "gf")
|
||||
err = j.Set("Name4", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name4").(g.Map)["Name"], "gf")
|
||||
arr := [3]int{1, 2, 3}
|
||||
err = j.Set("Name5", arr)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Name5").(g.Array)[0], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,70 +7,87 @@
|
||||
package gjson_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_Load_JSON(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_XML(t *testing.T) {
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
xml := `<?xml version="1.0"?>
|
||||
|
||||
<Output type="o">
|
||||
<itotalSize>0</itotalSize>
|
||||
<ipageSize>1</ipageSize>
|
||||
<ipageIndex>2</ipageIndex>
|
||||
<itotalRecords>GF框架</itotalRecords>
|
||||
<nworkOrderDtos/>
|
||||
<nworkOrderFrontXML/>
|
||||
</Output>`
|
||||
j, err := gjson.LoadContent(xml)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.itotalRecords"), "GF框架")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
@ -79,78 +96,102 @@ m:
|
||||
k: v
|
||||
"n": 123456789
|
||||
`)
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML2(t *testing.T) {
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a = ["1", "2", "3"]
|
||||
n = "123456789"
|
||||
|
||||
[m]
|
||||
k = "v"
|
||||
`)
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gjson.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML2(t *testing.T) {
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.NewUnsafe()
|
||||
gtest.Assert(j.Value(), nil)
|
||||
_, err := gjson.Decode(nil)
|
||||
gtest.AssertNE(err, nil)
|
||||
_, err = gjson.DecodeToJson(nil)
|
||||
gtest.AssertNE(err, nil)
|
||||
j, err = gjson.LoadContent(nil)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Value(), nil)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"""}`)
|
||||
gtest.AssertNE(err, nil)
|
||||
|
||||
j = gjson.New(&g.Map{"name": "gf"})
|
||||
gtest.Assert(j.GetString("name"), "gf")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ func Load(path string, unsafe...bool) (*Parser, error) {
|
||||
// LoadContent creates a Parser object from given content,
|
||||
// it checks the data type of <content> automatically,
|
||||
// supporting JSON, XML, YAML and TOML types of data.
|
||||
func LoadContent(data []byte, unsafe...bool) (*Parser, error) {
|
||||
func LoadContent(data interface{}, unsafe...bool) (*Parser, error) {
|
||||
if j, e := gjson.LoadContent(data, unsafe...); e == nil {
|
||||
return &Parser{j}, nil
|
||||
} else {
|
||||
|
||||
@ -7,202 +7,314 @@
|
||||
package gparser_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_New(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
v := j.Value().(g.Map)
|
||||
gtest.Assert(v["n"], 123456789)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewUnsafe(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.NewUnsafe(data)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gparser.VarToJson(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
value := g.Slice{1, 2, 3}
|
||||
gtest.Case(t, func() {
|
||||
b, err := gparser.VarToJson(value)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(b, []byte(`[1,2,3]`))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Decode(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SplitChar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
j.SetSplitChar(byte('#'))
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m#k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a#1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ViolenceCheck(t *testing.T) {
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
data := []byte(`{"m":{"a":[1,2,3], "v1.v2":"4"}}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.Get("m.a.2"), 3)
|
||||
gtest.Assert(j.Get("m.v1.v2"), nil)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("m.v1.v2"), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetToVar(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
var m map[string]string
|
||||
var n int
|
||||
var a []int
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
j.GetToVar("n", &n)
|
||||
j.GetToVar("m", &m)
|
||||
j.GetToVar("a", &a)
|
||||
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k" : "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
gtest.Assert(n, "123456789")
|
||||
gtest.Assert(m, g.Map{"k": "v"})
|
||||
gtest.Assert(a, g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetMap(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetArray(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetArray("n"), g.Array{123456789})
|
||||
gtest.Assert(j.GetArray("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.Assert(j.GetArray("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetString(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetString("n"), "123456789")
|
||||
gtest.AssertEQ(j.GetString("m"), `{"k":"v"}`)
|
||||
gtest.AssertEQ(j.GetString("a"), `[1,2,3]`)
|
||||
gtest.AssertEQ(j.GetString("i"), "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetStrings(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetInterfaces(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k":"v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1,2,3})
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.AssertEQ(j.GetInterfaces("n"), g.Array{123456789})
|
||||
gtest.AssertEQ(j.GetInterfaces("m"), g.Array{g.Map{"k": "v"}})
|
||||
gtest.AssertEQ(j.GetInterfaces("a"), g.Array{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Len("a"), 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
gtest.Assert(p.Len("a"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Append(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Get("a"), g.Slice{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b" : g.Slice{1},
|
||||
"c" : g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
err := p.Append("a", 2)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(p.Get("a"), 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a", 1)
|
||||
p.Append("a", 2)
|
||||
gtest.Assert(p.Get("a"), g.Slice{1, 2})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Append("a.b", 1)
|
||||
p.Append("a.c", 2)
|
||||
gtest.Assert(p.Get("a"), g.Map{
|
||||
"b": g.Slice{1},
|
||||
"c": g.Slice{2},
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(nil)
|
||||
p.Set("a", 1)
|
||||
err := p.Append("a", 2)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(p.Get("a"), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.New(`{"name":"gf","bool":true,"int":1,"float":1,"ints":[1,2],"floats":[1,2],"time":"2019-06-12","person": {"name": "gf"}}`)
|
||||
gtest.Assert(p.GetVar("name").String(), "gf")
|
||||
gtest.Assert(p.GetString("name"), "gf")
|
||||
gtest.Assert(p.GetBool("bool"), true)
|
||||
gtest.Assert(p.GetInt("int"), 1)
|
||||
gtest.Assert(p.GetInt8("int"), 1)
|
||||
gtest.Assert(p.GetInt16("int"), 1)
|
||||
gtest.Assert(p.GetInt32("int"), 1)
|
||||
gtest.Assert(p.GetInt64("int"), 1)
|
||||
gtest.Assert(p.GetUint("int"), 1)
|
||||
gtest.Assert(p.GetUint8("int"), 1)
|
||||
gtest.Assert(p.GetUint16("int"), 1)
|
||||
gtest.Assert(p.GetUint32("int"), 1)
|
||||
gtest.Assert(p.GetUint64("int"), 1)
|
||||
gtest.Assert(p.GetInts("ints")[0], 1)
|
||||
gtest.Assert(p.GetFloat32("float"), 1)
|
||||
gtest.Assert(p.GetFloat64("float"), 1)
|
||||
gtest.Assert(p.GetFloats("floats")[0], 1)
|
||||
gtest.Assert(p.GetTime("time").Format("2006-01-02"), "2019-06-12")
|
||||
gtest.Assert(p.GetGTime("time").Format("Y-m-d"), "2019-06-12")
|
||||
gtest.Assert(p.GetDuration("time").String(), "0s")
|
||||
name := struct {
|
||||
Name string
|
||||
}{}
|
||||
err := p.GetToStruct("person", &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
gtest.Assert(p.ToMap()["name"], "gf")
|
||||
err = p.ToStruct(&name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
p.Dump()
|
||||
|
||||
p = gparser.New(`[0,1,2]`)
|
||||
gtest.Assert(p.ToArray()[0], 0)
|
||||
|
||||
err = gparser.VarToStruct(`{"name":"gf"}`, &name)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(name.Name, "gf")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Convert2(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
xmlArr := []byte{60, 114, 111, 111, 116, 47, 62}
|
||||
p := gparser.New(`<root></root>`)
|
||||
arr, err := p.ToXml("root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
arr, err = gparser.VarToXml(`<root></root>`, "root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
|
||||
arr, err = p.ToXmlIndent("root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
arr, err = gparser.VarToXmlIndent(`<root></root>`, "root")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, xmlArr)
|
||||
|
||||
p = gparser.New(`{"name":"gf"}`)
|
||||
str, err := p.ToJsonString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, `{"name":"gf"}`)
|
||||
str, err = gparser.VarToJsonString(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, `{"name":"gf"}`)
|
||||
|
||||
jsonIndentArr := []byte{123, 10, 9, 34, 110, 97, 109, 101, 34, 58, 32, 34, 103, 102, 34, 10, 125}
|
||||
arr, err = p.ToJsonIndent()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, jsonIndentArr)
|
||||
arr, err = gparser.VarToJsonIndent(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, jsonIndentArr)
|
||||
|
||||
str, err = p.ToJsonIndentString()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "{\n\t\"name\": \"gf\"\n}")
|
||||
str, err = gparser.VarToJsonIndentString(`{"name":"gf"}`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(str, "{\n\t\"name\": \"gf\"\n}")
|
||||
|
||||
yamlArr := []byte{124, 50, 10, 10, 32, 32, 110, 97, 109, 101, 58, 103, 102, 10}
|
||||
p = gparser.New(`
|
||||
name:gf
|
||||
`)
|
||||
arr, err = p.ToYaml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, yamlArr)
|
||||
arr, err = gparser.VarToYaml(`
|
||||
name:gf
|
||||
`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, yamlArr)
|
||||
|
||||
tomlArr := []byte{110, 97, 109, 101, 32, 61, 32, 34, 103, 102, 34, 10}
|
||||
p = gparser.New(`
|
||||
name= "gf"
|
||||
`)
|
||||
arr, err = p.ToToml()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, tomlArr)
|
||||
arr, err = gparser.VarToToml(`
|
||||
name= "gf"
|
||||
`)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(arr, tomlArr)
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,70 +7,88 @@
|
||||
package gparser_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_Load_JSON(t *testing.T) {
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// JSON
|
||||
gtest.Case(t, func() {
|
||||
path := "test.json"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_XML(t *testing.T) {
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.xml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("doc.n"), "123456789")
|
||||
gtest.Assert(j.Get("doc.m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("doc.m.k"), "v")
|
||||
gtest.Assert(j.Get("doc.a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("doc.a.1"), 2)
|
||||
})
|
||||
|
||||
// XML
|
||||
gtest.Case(t, func() {
|
||||
xml := `<?xml version="1.0"?>
|
||||
|
||||
<Output type="o">
|
||||
<itotalSize>0</itotalSize>
|
||||
<ipageSize>1</ipageSize>
|
||||
<ipageIndex>2</ipageIndex>
|
||||
<itotalRecords>GF框架</itotalRecords>
|
||||
<nworkOrderDtos/>
|
||||
<nworkOrderFrontXML/>
|
||||
</Output>`
|
||||
j, err := gparser.LoadContent(xml)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("Output.ipageIndex"), "2")
|
||||
gtest.Assert(j.Get("Output.itotalRecords"), "GF框架")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
@ -79,78 +97,93 @@ m:
|
||||
k: v
|
||||
"n": 123456789
|
||||
`)
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// YAML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.yaml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YAML2(t *testing.T) {
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i : 123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML1(t *testing.T) {
|
||||
data := []byte(`
|
||||
data := []byte(`
|
||||
a = ["1", "2", "3"]
|
||||
n = "123456789"
|
||||
|
||||
[m]
|
||||
k = "v"
|
||||
`)
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
// TOML
|
||||
gtest.Case(t, func() {
|
||||
path := "test.toml"
|
||||
gfile.PutBinContents(path, data)
|
||||
defer gfile.Remove(path)
|
||||
j, err := gparser.Load(path)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("n"), "123456789")
|
||||
gtest.Assert(j.Get("m"), g.Map{"k": "v"})
|
||||
gtest.Assert(j.Get("m.k"), "v")
|
||||
gtest.Assert(j.Get("a"), g.Slice{1, 2, 3})
|
||||
gtest.Assert(j.Get("a.1"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_TOML2(t *testing.T) {
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
data := []byte("i=123456789")
|
||||
gtest.Case(t, func() {
|
||||
j, err := gparser.LoadContent(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.Get("i"), "123456789")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_Nil(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
p := gparser.NewUnsafe()
|
||||
gtest.Assert(p.Value(), nil)
|
||||
file := "test22222.json"
|
||||
filePath := gfile.Pwd() + gfile.Separator + file
|
||||
ioutil.WriteFile(filePath, []byte("{"), 0644)
|
||||
defer gfile.Remove(filePath)
|
||||
_, err := gparser.Load(file)
|
||||
gtest.AssertNE(err, nil)
|
||||
_, err = gparser.LoadContent("{")
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -5,14 +5,12 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gxml provides accessing and converting for XML content.
|
||||
//
|
||||
// XML数据格式解析。
|
||||
package gxml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/encoding/gcharset"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/third/github.com/axgle/mahonia"
|
||||
"github.com/gogf/gf/third/github.com/clbanning/mxj"
|
||||
"strings"
|
||||
)
|
||||
@ -52,33 +50,27 @@ func ToJson(content []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// XML字符集预处理
|
||||
// @author wenzi1
|
||||
// @date 20180604 修复并发安全问题,改为如果非UTF8字符集则先做字符集转换
|
||||
func convert(xmlbyte []byte) (res []byte, err error) {
|
||||
func convert(xml []byte) (res []byte, err error) {
|
||||
patten := `<\?xml.*encoding\s*=\s*['|"](.*?)['|"].*\?>`
|
||||
matchStr, err := gregex.MatchString(patten, string(xmlbyte))
|
||||
matchStr, err := gregex.MatchString(patten, string(xml))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xmlEncode := "UTF-8"
|
||||
if len(matchStr) == 2 {
|
||||
xmlEncode = matchStr[1]
|
||||
}
|
||||
|
||||
s := mahonia.GetCharset(xmlEncode)
|
||||
if s == nil {
|
||||
return nil, fmt.Errorf("not support charset:%s\n", xmlEncode)
|
||||
}
|
||||
|
||||
res, err = gregex.Replace(patten, []byte(""), []byte(xmlbyte))
|
||||
xmlEncode = strings.ToUpper(xmlEncode)
|
||||
res, err = gregex.Replace(patten, []byte(""), xml)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !strings.EqualFold(s.Name, "UTF-8") {
|
||||
res = []byte(s.NewDecoder().ConvertString(string(res)))
|
||||
if xmlEncode != "UTF-8" && xmlEncode != "UTF8" {
|
||||
dst, err := gcharset.Convert("UTF-8", xmlEncode, string(res))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = []byte(dst)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/gogf/gf/g/encoding/gcharset"
|
||||
"github.com/gogf/gf/g/encoding/gparser"
|
||||
"github.com/gogf/gf/g/encoding/gxml"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -23,6 +24,12 @@ var testData = []struct {
|
||||
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"},
|
||||
}
|
||||
|
||||
var testErrData = []struct {
|
||||
utf8, other, otherEncoding string
|
||||
}{
|
||||
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"},
|
||||
}
|
||||
|
||||
func buildXml(charset string, str string) (string, string) {
|
||||
head := `<?xml version="1.0" encoding="UTF-8"?>`
|
||||
srcXml := strings.Replace(head, "UTF-8", charset, -1)
|
||||
@ -112,7 +119,7 @@ func Test_Encode(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("encode error.")
|
||||
}
|
||||
t.Logf("%s\n", string(xmlStr))
|
||||
//t.Logf("%s\n", string(xmlStr))
|
||||
|
||||
res := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string></root>`
|
||||
if string(xmlStr) != res {
|
||||
@ -130,11 +137,45 @@ func Test_EncodeIndent(t *testing.T) {
|
||||
}
|
||||
m["root"] = interface{}(v)
|
||||
|
||||
xmlStr, err := gxml.EncodeWithIndent(m, "xml")
|
||||
_, err := gxml.EncodeWithIndent(m, "xml")
|
||||
if err != nil {
|
||||
t.Errorf("encodeWithIndent error.")
|
||||
}
|
||||
|
||||
t.Logf("%s\n", string(xmlStr))
|
||||
//t.Logf("%s\n", string(xmlStr))
|
||||
|
||||
}
|
||||
|
||||
func TestErrXml(t *testing.T) {
|
||||
for _, v := range testErrData {
|
||||
srcXml, dstXml := buildXml(v.otherEncoding, v.utf8)
|
||||
if len(srcXml) == 0 && len(dstXml) == 0 {
|
||||
t.Errorf("build xml string error. srcEncoding:%s, src:%s, utf8:%s", v.otherEncoding, v.other, v.utf8)
|
||||
}
|
||||
|
||||
srcXml = strings.Replace(srcXml, "gbk", "XXX", -1)
|
||||
_, err := gxml.ToJson([]byte(srcXml))
|
||||
if err == nil {
|
||||
t.Errorf("srcXml to json should be failed. %s", srcXml)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrCase(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
errXml := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string>`
|
||||
_, err := gxml.ToJson([]byte(errXml))
|
||||
if err == nil {
|
||||
t.Errorf("unexpected value: nil")
|
||||
}
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
errXml := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string>`
|
||||
_, err := gxml.Decode([]byte(errXml))
|
||||
if err == nil {
|
||||
t.Errorf("unexpected value: nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -61,13 +61,13 @@ func SetIfNotExist(key string, value interface{}) bool {
|
||||
}
|
||||
|
||||
// View returns an instance of View with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func View(name ...string) *gview.View {
|
||||
return gview.Instance(name ...)
|
||||
}
|
||||
|
||||
// Config returns an instance of View with default settings.
|
||||
// The param <name> is the name for the instance.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func Config(name ...string) *gcfg.Config {
|
||||
return gcfg.Instance(name ...)
|
||||
}
|
||||
@ -219,13 +219,13 @@ func Redis(name...string) *gredis.Redis {
|
||||
Pass : array[4],
|
||||
})
|
||||
} else {
|
||||
glog.Errorfln(`invalid redis node configuration: "%s"`, line)
|
||||
glog.Errorf(`invalid redis node configuration: "%s"`, line)
|
||||
}
|
||||
} else {
|
||||
glog.Errorfln(`configuration for redis not found for group "%s"`, group)
|
||||
glog.Errorf(`configuration for redis not found for group "%s"`, group)
|
||||
}
|
||||
} else {
|
||||
glog.Errorfln(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
|
||||
glog.Errorf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -47,7 +47,7 @@ func Database(name...string) gdb.DB {
|
||||
return gins.Database(name...)
|
||||
}
|
||||
|
||||
// Alias of Database. See Database.
|
||||
// DB is alias of Database. See Database.
|
||||
func DB(name...string) gdb.DB {
|
||||
return gins.Database(name...)
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package cmdenv provides access to certain variable for both command options and environment.
|
||||
package cmdenv
|
||||
|
||||
import (
|
||||
@ -18,7 +19,12 @@ var (
|
||||
cmdOptions = make(map[string]string)
|
||||
)
|
||||
|
||||
func init() {
|
||||
func init() {
|
||||
doInit()
|
||||
}
|
||||
|
||||
// doInit does the initialization for this package.
|
||||
func doInit() {
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
result := reg.FindStringSubmatch(os.Args[i])
|
||||
@ -28,10 +34,13 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定名称的命令行参数,当不存在时获取环境变量参数,皆不存在时,返回给定的默认值。
|
||||
// 规则:
|
||||
// 1、命令行参数以小写字母格式,使用: gf.包名.变量名 传递;
|
||||
// 2、环境变量参数以大写字母格式,使用: GF_包名_变量名 传递;
|
||||
// Get returns the command line argument of the specified <key>.
|
||||
// If the argument does not exist, then it returns the environment variable with specified <key>.
|
||||
// It returns the default value <def> if none of them exists.
|
||||
//
|
||||
// Fetching Rules:
|
||||
// 1. Command line arguments are in lowercase format, eg: gf.<package name>.<variable name>;
|
||||
// 2. Environment arguments are in uppercase format, eg: GF_<package name>_<variable name>;
|
||||
func Get(key string, def...interface{}) *gvar.Var {
|
||||
value := interface{}(nil)
|
||||
if len(def) > 0 {
|
||||
|
||||
29
g/internal/cmdenv/cmdenv_test.go
Normal file
29
g/internal/cmdenv/cmdenv_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package cmdenv
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Get(t *testing.T) {
|
||||
os.Args = []string{"--gf.test.value1=111"}
|
||||
os.Setenv("GF_TEST_VALUE1", "222")
|
||||
os.Setenv("GF_TEST_VALUE2", "333")
|
||||
doInit()
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(Get("gf.test.value1").String(), "111")
|
||||
gtest.Assert(Get("gf.test.value2").String(), "333")
|
||||
gtest.Assert(Get("gf.test.value3").String(), "")
|
||||
gtest.Assert(Get("gf.test.value3", 1).String(), "1")
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,15 +4,16 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package empty provides checks for empty variables.
|
||||
package empty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 判断给定的变量是否为空。
|
||||
// 整型为0, 布尔为false, slice/map长度为0, 其他为nil的情况,都为空。
|
||||
// 为空时返回true,否则返回false。
|
||||
// IsEmpty checks whether given <value> empty.
|
||||
// It returns true if <value> is in: 0, nil, false, "", len(slice/map/chan) == 0.
|
||||
// Or else it returns true.
|
||||
func IsEmpty(value interface{}) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
@ -35,17 +36,22 @@ func IsEmpty(value interface{}) bool {
|
||||
case string: return value == ""
|
||||
case []byte: return len(value) == 0
|
||||
default:
|
||||
// 最后通过反射来判断
|
||||
// Finally using reflect.
|
||||
rv := reflect.ValueOf(value)
|
||||
if rv.IsNil() {
|
||||
return true
|
||||
}
|
||||
kind := rv.Kind()
|
||||
switch kind {
|
||||
case reflect.Map: fallthrough
|
||||
case reflect.Slice: fallthrough
|
||||
case reflect.Array:
|
||||
switch rv.Kind() {
|
||||
case reflect.Chan,
|
||||
reflect.Map,
|
||||
reflect.Slice,
|
||||
reflect.Array:
|
||||
return rv.Len() == 0
|
||||
|
||||
case reflect.Func,
|
||||
reflect.Ptr,
|
||||
reflect.Interface,
|
||||
reflect.UnsafePointer:
|
||||
if rv.IsNil() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package mutex provides switch for sync.Mutex for concurrent safe feature.
|
||||
package mutex
|
||||
|
||||
import "sync"
|
||||
|
||||
// Mutex的封装,支持对并发安全开启/关闭的控制。
|
||||
type Mutex struct {
|
||||
sync.Mutex
|
||||
safe bool
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package rwmutex provides switch for sync.RWMutex for concurrent safe feature.
|
||||
package rwmutex
|
||||
|
||||
import "sync"
|
||||
|
||||
@ -180,6 +180,17 @@ func (c *Client) Post(url string, data...interface{}) (*ClientResponse, error) {
|
||||
cookies : make(map[string]string),
|
||||
}
|
||||
r.Response = resp
|
||||
// 浏览器模式
|
||||
if c.browserMode {
|
||||
now := time.Now()
|
||||
for _, v := range r.Cookies() {
|
||||
if v.Expires.UnixNano() < now.UnixNano() {
|
||||
delete(c.cookies, v.Name)
|
||||
} else {
|
||||
c.cookies[v.Name] = v.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -258,7 +269,7 @@ func (c *Client) DoRequestContent(method string, url string, data...interface{})
|
||||
return string(response.ReadAll())
|
||||
}
|
||||
|
||||
// 请求并返回response对象,该方法支持二进制提交数据
|
||||
// 请求并返回response对象
|
||||
func (c *Client) DoRequest(method, url string, data...interface{}) (*ClientResponse, error) {
|
||||
if strings.EqualFold("POST", method) {
|
||||
return c.Post(url, data...)
|
||||
|
||||
@ -142,16 +142,16 @@ func (r *Request) GetPostMap(def...map[string]string) map[string]string {
|
||||
}
|
||||
|
||||
// 将所有的request参数映射到struct属性上,参数object应当为一个struct对象的指针, mapping为非必需参数,自定义参数与属性的映射关系
|
||||
func (r *Request) GetPostToStruct(object interface{}, mapping...map[string]string) error {
|
||||
tagmap := r.getStructParamsTagMap(object)
|
||||
func (r *Request) GetPostToStruct(pointer interface{}, mapping...map[string]string) error {
|
||||
tagMap := r.getStructParamsTagMap(pointer)
|
||||
if len(mapping) > 0 {
|
||||
for k, v := range mapping[0] {
|
||||
tagmap[k] = v
|
||||
tagMap[k] = v
|
||||
}
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
for k, v := range r.GetPostMap() {
|
||||
params[k] = v
|
||||
}
|
||||
return gconv.Struct(params, object, tagmap)
|
||||
return gconv.Struct(params, pointer, tagMap)
|
||||
}
|
||||
@ -150,8 +150,8 @@ func (r *Request) GetQueryMap(def... map[string]string) map[string]string {
|
||||
}
|
||||
|
||||
// 将所有的get参数映射到struct属性上,参数object应当为一个struct对象的指针, mapping为非必需参数,自定义参数与属性的映射关系
|
||||
func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]string) error {
|
||||
tagmap := r.getStructParamsTagMap(object)
|
||||
func (r *Request) GetQueryToStruct(pointer interface{}, mapping...map[string]string) error {
|
||||
tagmap := r.getStructParamsTagMap(pointer)
|
||||
if len(mapping) > 0 {
|
||||
for k, v := range mapping[0] {
|
||||
tagmap[k] = v
|
||||
@ -161,5 +161,5 @@ func (r *Request) GetQueryToStruct(object interface{}, mapping...map[string]stri
|
||||
for k, v := range r.GetQueryMap() {
|
||||
params[k] = v
|
||||
}
|
||||
return gconv.Struct(params, object, tagmap)
|
||||
return gconv.Struct(params, pointer, tagmap)
|
||||
}
|
||||
@ -133,10 +133,10 @@ func (r *Request) GetRequestMap(def...map[string]string) map[string]string {
|
||||
|
||||
// 将所有的request参数映射到struct属性上,参数object应当为一个struct对象的指针, mapping为非必需参数,自定义参数与属性的映射关系
|
||||
func (r *Request) GetRequestToStruct(pointer interface{}, mapping...map[string]string) error {
|
||||
tagmap := r.getStructParamsTagMap(pointer)
|
||||
tagMap := r.getStructParamsTagMap(pointer)
|
||||
if len(mapping) > 0 {
|
||||
for k, v := range mapping[0] {
|
||||
tagmap[k] = v
|
||||
tagMap[k] = v
|
||||
}
|
||||
}
|
||||
params := make(map[string]interface{})
|
||||
@ -148,6 +148,6 @@ func (r *Request) GetRequestToStruct(pointer interface{}, mapping...map[string]s
|
||||
params = j.ToMap()
|
||||
}
|
||||
}
|
||||
return gconv.Struct(params, pointer, tagmap)
|
||||
return gconv.Struct(params, pointer, tagMap)
|
||||
}
|
||||
|
||||
|
||||
@ -134,7 +134,9 @@ func (r *Response) WriteStatus(status int, content...string) {
|
||||
// 状态码注册回调函数处理
|
||||
if status != http.StatusOK {
|
||||
if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
|
||||
f(r.request)
|
||||
r.Server.niceCallFunc(func() {
|
||||
f(r.request)
|
||||
})
|
||||
// 防止多次设置(http: multiple response.WriteHeader calls)
|
||||
if r.Status == 0 {
|
||||
r.WriteHeader(status)
|
||||
|
||||
@ -52,7 +52,10 @@ func (r *Response) buildInVars(params...map[string]interface{}) map[string]inter
|
||||
} else {
|
||||
vars = make(map[string]interface{})
|
||||
}
|
||||
vars["Config"] = gins.Config().GetMap("")
|
||||
// 当配置文件不存在时就不赋值该模板变量,不然会报错
|
||||
if c := gins.Config(); c.FilePath() != "" {
|
||||
vars["Config"] = c.GetMap("")
|
||||
}
|
||||
vars["Cookie"] = r.request.Cookie.Map()
|
||||
vars["Session"] = r.request.Session.Map()
|
||||
vars["Get"] = r.request.GetQueryMap()
|
||||
|
||||
@ -389,7 +389,7 @@ func (s *Server) Run() error {
|
||||
// 阻塞等待服务执行完成
|
||||
<- s.closeChan
|
||||
|
||||
glog.Printfln("%d: all servers shutdown", gproc.Pid())
|
||||
glog.Printf("%d: all servers shutdown", gproc.Pid())
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ func Wait() {
|
||||
// 阻塞等待服务执行完成
|
||||
<- allDoneChan
|
||||
|
||||
glog.Printfln("%d: all servers shutdown", gproc.Pid())
|
||||
glog.Printf("%d: all servers shutdown", gproc.Pid())
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ func forkReloadProcess(newExeFilePath...string) error {
|
||||
buffer, _ := gjson.Encode(sfm)
|
||||
p.Env = append(p.Env, gADMIN_ACTION_RELOAD_ENVKEY + "=" + string(buffer))
|
||||
if _, err := p.Start(); err != nil {
|
||||
glog.Errorfln("%d: fork process failed, error:%s, %s", gproc.Pid(), err.Error(), string(buffer))
|
||||
glog.Errorf("%d: fork process failed, error:%s, %s", gproc.Pid(), err.Error(), string(buffer))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -147,7 +147,7 @@ func forkRestartProcess(newExeFilePath...string) error {
|
||||
env = append(env, gADMIN_ACTION_RESTART_ENVKEY + "=1")
|
||||
p := gproc.NewProcess(path, os.Args, env)
|
||||
if _, err := p.Start(); err != nil {
|
||||
glog.Errorfln("%d: fork process failed, error:%s", gproc.Pid(), err.Error())
|
||||
glog.Errorf("%d: fork process failed, error:%s", gproc.Pid(), err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -197,14 +197,14 @@ func restartWebServers(signal string, newExeFilePath...string) error {
|
||||
}
|
||||
} else {
|
||||
if err := forkReloadProcess(newExeFilePath...); err != nil {
|
||||
glog.Printfln("%d: server restarts failed", gproc.Pid())
|
||||
glog.Printf("%d: server restarts failed", gproc.Pid())
|
||||
serverProcessStatus.Set(gADMIN_ACTION_NONE)
|
||||
return err
|
||||
} else {
|
||||
if len(signal) > 0 {
|
||||
glog.Printfln("%d: server restarting by signal: %s", gproc.Pid(), signal)
|
||||
glog.Printf("%d: server restarting by signal: %s", gproc.Pid(), signal)
|
||||
} else {
|
||||
glog.Printfln("%d: server restarting by web admin", gproc.Pid())
|
||||
glog.Printf("%d: server restarting by web admin", gproc.Pid())
|
||||
}
|
||||
|
||||
}
|
||||
@ -216,12 +216,12 @@ func restartWebServers(signal string, newExeFilePath...string) error {
|
||||
func shutdownWebServers(signal...string) {
|
||||
serverProcessStatus.Set(gADMIN_ACTION_SHUTINGDOWN)
|
||||
if len(signal) > 0 {
|
||||
glog.Printfln("%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
|
||||
glog.Printf("%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
|
||||
// 在终端信号下,立即执行关闭操作
|
||||
forceCloseWebServers()
|
||||
allDoneChan <- struct{}{}
|
||||
} else {
|
||||
glog.Printfln("%d: server shutting down by api", gproc.Pid())
|
||||
glog.Printf("%d: server shutting down by api", gproc.Pid())
|
||||
// 非终端信号下,异步1秒后再执行关闭,
|
||||
// 目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了)
|
||||
gtimer.SetTimeout(time.Second, func() {
|
||||
|
||||
@ -46,6 +46,7 @@ type ServerConfig struct {
|
||||
IdleTimeout time.Duration // 等待超时
|
||||
MaxHeaderBytes int // 最大的header长度
|
||||
TLSConfig tls.Config
|
||||
KeepAlive bool
|
||||
|
||||
// 静态文件配置
|
||||
IndexFiles []string // 默认访问的文件列表
|
||||
@ -96,6 +97,7 @@ var defaultServerConfig = ServerConfig {
|
||||
WriteTimeout : 60 * time.Second,
|
||||
IdleTimeout : 60 * time.Second,
|
||||
MaxHeaderBytes : 1024,
|
||||
KeepAlive : true,
|
||||
|
||||
IndexFiles : []string{"index.html", "index.htm"},
|
||||
IndexFolder : false,
|
||||
@ -316,6 +318,15 @@ func (s *Server) SetRouterCacheExpire(expire int) {
|
||||
s.config.RouterCacheExpire = expire
|
||||
}
|
||||
|
||||
// 设置KeepAlive
|
||||
func (s *Server) SetKeepAlive(enabled bool) {
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
|
||||
return
|
||||
}
|
||||
s.config.KeepAlive = enabled
|
||||
}
|
||||
|
||||
// 获取WebServer名称
|
||||
func (s *Server) GetName() string {
|
||||
return s.name
|
||||
|
||||
@ -21,9 +21,9 @@ import (
|
||||
|
||||
// 优雅的Web Server对象封装
|
||||
type gracefulServer struct {
|
||||
fd uintptr
|
||||
addr string
|
||||
httpServer *http.Server
|
||||
fd uintptr // 热重启时传递的socket监听文件句柄
|
||||
addr string // 监听地址信息
|
||||
httpServer *http.Server // 底层http.Server
|
||||
rawListener net.Listener // 原始listener
|
||||
listener net.Listener // 接口化封装的listener
|
||||
isHttps bool // 是否HTTPS
|
||||
@ -45,7 +45,7 @@ func (s *Server) newGracefulServer(addr string, fd...int) *gracefulServer {
|
||||
|
||||
// 生成一个底层的Web Server对象
|
||||
func (s *Server) newHttpServer(addr string) *http.Server {
|
||||
return &http.Server {
|
||||
server := &http.Server {
|
||||
Addr : addr,
|
||||
Handler : s.config.Handler,
|
||||
ReadTimeout : s.config.ReadTimeout,
|
||||
@ -53,6 +53,8 @@ func (s *Server) newHttpServer(addr string) *http.Server {
|
||||
IdleTimeout : s.config.IdleTimeout,
|
||||
MaxHeaderBytes : s.config.MaxHeaderBytes,
|
||||
}
|
||||
server.SetKeepAlivesEnabled(s.config.KeepAlive)
|
||||
return server
|
||||
}
|
||||
|
||||
// 执行HTTP监听
|
||||
@ -128,7 +130,7 @@ func (s *gracefulServer) doServe() error {
|
||||
if s.fd != 0 {
|
||||
action = "reloaded"
|
||||
}
|
||||
glog.Printfln("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
|
||||
glog.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
|
||||
s.status = SERVER_STATUS_RUNNING
|
||||
err := s.httpServer.Serve(s.listener)
|
||||
s.status = SERVER_STATUS_STOPPED
|
||||
@ -171,7 +173,7 @@ func (s *gracefulServer) shutdown() {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
||||
glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +183,7 @@ func (s *gracefulServer) close() {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Close(); err != nil {
|
||||
glog.Errorfln("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin
|
||||
caller := s.getHandlerRegisterCallerLine(handler)
|
||||
if len(hook) == 0 {
|
||||
if item, ok := s.routesMap[regkey]; ok {
|
||||
glog.Errorfln(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
|
||||
glog.Errorf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ func (d *Domain) Group(prefix...string) *RouterGroup {
|
||||
func (g *RouterGroup) Bind(items []GroupItem) {
|
||||
for _, item := range items {
|
||||
if len(item) < 3 {
|
||||
glog.Fatalfln("invalid router item: %s", item)
|
||||
glog.Fatalf("invalid router item: %s", item)
|
||||
}
|
||||
if strings.EqualFold(gconv.String(item[0]), "REST") {
|
||||
g.bind("REST", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2])
|
||||
@ -124,7 +124,7 @@ func (g *RouterGroup) bind(bindType string, pattern string, object interface{},
|
||||
if len(g.prefix) > 0 {
|
||||
domain, method, path, err := g.server.parsePattern(pattern)
|
||||
if err != nil {
|
||||
glog.Fatalfln("invalid pattern: %s", pattern)
|
||||
glog.Fatalf("invalid pattern: %s", pattern)
|
||||
}
|
||||
if bindType == "HANDLER" {
|
||||
pattern = g.server.serveHandlerKey(method, g.prefix + "/" + strings.TrimLeft(path, "/"), domain)
|
||||
@ -196,7 +196,7 @@ func (g *RouterGroup) bind(bindType string, pattern string, object interface{},
|
||||
g.domain.BindHookHandler(pattern, methods[0], h)
|
||||
}
|
||||
} else {
|
||||
glog.Fatalfln("invalid hook handler for pattern:%s", pattern)
|
||||
glog.Fatalf("invalid hook handler for pattern:%s", pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,11 +50,11 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) {
|
||||
if _, ok := v.Method(i).Interface().(func()); !ok {
|
||||
if len(methodMap) > 0 {
|
||||
// 指定的方法名称注册,那么需要使用错误提示
|
||||
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
pkgPath, ctlName, mname, v.Method(i).Type().String())
|
||||
} else {
|
||||
// 否则只是Debug提示
|
||||
glog.Debugfln(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
|
||||
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
|
||||
pkgPath, ctlName, mname, v.Method(i).Type().String())
|
||||
}
|
||||
continue
|
||||
@ -108,7 +108,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string
|
||||
ctlName = fmt.Sprintf(`(%s)`, ctlName)
|
||||
}
|
||||
if _, ok := fval.Interface().(func()); !ok {
|
||||
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
pkgPath, ctlName, mname, fval.Type().String())
|
||||
return
|
||||
}
|
||||
@ -147,7 +147,7 @@ func (s *Server)BindControllerRest(pattern string, c Controller) {
|
||||
ctlName = fmt.Sprintf(`(%s)`, ctlName)
|
||||
}
|
||||
if _, ok := v.Method(i).Interface().(func()); !ok {
|
||||
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
|
||||
pkgPath, ctlName, mname, v.Method(i).Type().String())
|
||||
return
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user