main.lua 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. -- LuaTools需要PROJECT和VERSION这两个信息
  2. PROJECT = "demo_str_test"
  3. VERSION = "1.0.0"
  4. LOG_TAG = "str"
  5. --[[
  6. 用例0101 字符串定义与基本操作
  7. 1. lua的字符串是带长度, 不依赖0x00作为结束字符串, 可以包含任意数据
  8. 2. lua的字符串是不可变的, 就不能直接修改字符串的一个字符, 修改字符会返回一个新的字符串
  9. ]]--
  10. function tc0101_str_base_operation()
  11. -- 双引号定义字符串,若字符串中包含了单引号,使用双引号来定义字符串会避免转义字符的需要
  12. local str1 = "Hello 'LuatOS'"
  13. -- 单引号定义字符串,若字符串中包含了双引号,使用单引号来定义字符串会避免转义字符的需要
  14. local str2 = '你好"LuatOS"'
  15. -- 双方括号定义多行字符串
  16. local str_lines = [[
  17. Hello Air8101!
  18. Hello "LuatOS"!\r\n
  19. ]]
  20. log.info(LOG_TAG, "双括号定义单行string:", str1)
  21. log.info(LOG_TAG, "单引号定义单行string:", str2)
  22. log.info(LOG_TAG, "双方括号定义多行string:", str_lines)
  23. -- 反斜杠转义字符
  24. local str3 = "Hello\nLuatOS"
  25. log.info(LOG_TAG, "string转义换行:", str3)
  26. -- 字符串长度获取的方式: #操作符或string.len
  27. local len1 = string.len(str1)
  28. log.info(LOG_TAG, str1 .. " len=", len1)
  29. assert(len1 == 14)
  30. -- 使用UTF-8字符编码的情况下一个中文字符一般占3个字节
  31. local len2 = #str2
  32. log.info(LOG_TAG, str2 .. " len=", len2)
  33. assert(len2 == 14)
  34. -- 多行字符串长度统计包括空格换行等不可见字符,(`[[`后面紧跟的一个换行符不包含在字符串内,不识别转义序列)
  35. local len_lines = #str_lines
  36. log.info(LOG_TAG, str_lines .. " len=", len_lines)
  37. assert(len_lines == 35)
  38. -- 字符串拼接, 使用".."来拼接,
  39. -- 只能为数字或字符串(nil/boolean可以用tostring转换)
  40. -- 左右两边有空格(与数字拼接时必需)
  41. local str4 = "hello " .. "luat " .. 2025
  42. log.info(LOG_TAG, str4 .. " len=", #str4)
  43. assert(str4 == "hello luat 2025")
  44. str4 = "display " .. tostring(nil) .. " and " .. tostring(false)
  45. log.info(LOG_TAG, str4 .. " len=", #str4)
  46. assert(str4 == "display nil and false")
  47. end
  48. --[[
  49. 用例0102 字符串模式匹配-查找
  50. ]]--
  51. function tc0102_str_pattern_matching()
  52. local text = "hello-air8101!hello luatos 2025!"
  53. local s,e,sub_str
  54. --[[
  55. string.find
  56. 查找字符串中是否包含匹配的pattern,并返回匹配的位置
  57. ]]--
  58. -- 仅指定pattern, 默认打开模式匹配,如果pattern含lua支持匹配的魔法字符,需用%符号,转义为原生字符才能匹配
  59. s,e = string.find(text, "hello%-air")
  60. log.info(LOG_TAG, "match hello-air", s, e)
  61. assert(s == 1 and e == 9)
  62. -- 注意:这里需要带括号()返回捕获匹配子串,否则返回nil
  63. s, e, sub_str = string.find(text, "(%d%d%d%d)")
  64. log.info(LOG_TAG, "match %d%d%d%d", s, e, sub_str)
  65. assert(s == 10 and e == 13 and sub_str == "8101")
  66. -- 指定起始位置init
  67. s, e= string.find(text, "hello", 13)
  68. log.info(LOG_TAG, "match hello", s, e)
  69. assert(s == 15 and e == 19)
  70. -- 指定起始位置init,关闭模式匹配(plain=true)
  71. s, e, sub_str = string.find(text, "%d%d%d%d", 15, true)
  72. log.info(LOG_TAG, "match %d%d%d%d", s, e, sub_str)
  73. assert(s == nil and e == nil and sub_str == nil)
  74. --[[
  75. string.match,
  76. 查找字符串中第一个匹配pattern的字符串
  77. ]]--
  78. -- 不带括号时返回匹配的全字符串
  79. sub_str = string.match(text, "%d%d%d%d")
  80. log.info(LOG_TAG, "match %d%d%d%d", sub_str)
  81. assert(sub_str == "8101")
  82. -- 指定起始位置init,带括号时只返回括号中的捕获匹配子串
  83. sub_str = string.match(text, "%d(%d%d)%d", 15)
  84. log.info(LOG_TAG, "match %d(%d%d)%d", sub_str)
  85. assert(sub_str == "02")
  86. --[[
  87. string.gmatch,
  88. 返回一个迭代器,依次匹配字符串中的所有符合模式的子串
  89. ]]--
  90. local str_table = {}
  91. local iter_func = string.gmatch(text, "%d%d%d%d")
  92. for val in iter_func do
  93. log.info(LOG_TAG, "gmatch ", val)
  94. table.insert(str_table, val)
  95. end
  96. assert(str_table[1] == "8101" and str_table[2] == "2025")
  97. end
  98. --[[
  99. 用例0103 字符串模式匹配-替换操作
  100. ]]--
  101. function tc0103_str_replace()
  102. local text = "hello air8101!hello luatos 2025!"
  103. local new_text,times
  104. --[[
  105. string.gsub,
  106. 替换字符串中的所有或部分匹配的模式,
  107. ]]--
  108. -- 替换参数为字符串, 指定匹配"hello"字符串,第三参数指定替换为"hi", 第四个参数指定替换次数,替换1次,将hello替换成hi
  109. local new_text = string.gsub(text, "hello", "hi", 1)
  110. -- 返回值: new_text为"hi air8101!hello luatos 2025!"
  111. log.info(LOG_TAG, text .. " change to ", new_text)
  112. assert(new_text == "hi air8101!hello luatos 2025!")
  113. -- 指定pattern为(%w+)匹配所有字母及数字,把匹配到的子串作为第一组捕获(这里一对括号共一组捕获),通过%1来引用
  114. -- 替换动作为重复第一组捕获中间加","间隔,全部匹配替换
  115. local new_text, times = string.gsub(text, "(%w+)", "%1,%1")
  116. log.info(LOG_TAG, text .. " change to ", new_text)
  117. assert(new_text == "hello,hello air8101,air8101!hello,hello luatos,luatos 2025,2025!" and times == 5)
  118. -- 替换参数为table,匹配到的字符串当做键在表中查找,找到后用键对应值做替换, 取值第二个返回参数为替换次数
  119. local str_tab = {hello = "hi"}
  120. new_text, times = string.gsub(text, "hello", str_tab)
  121. log.info(LOG_TAG, text .. " change to ", new_text)
  122. assert(new_text == "hi air8101!hi luatos 2025!" and times == 2)
  123. -- 替换参数为function,查找到的字符当做函数的参数传入替换函数,变更字符
  124. new_text, times = string.gsub(text, "hello", function (str)
  125. return string.upper(str)
  126. end)
  127. log.info(LOG_TAG, text .. " change to ", new_text)
  128. assert(new_text == "HELLO air8101!HELLO luatos 2025!" and times == 2)
  129. end
  130. --[[
  131. 用例0104 字符截取、复制与反转操作
  132. ]]--
  133. function tc0104_str_truncate_copy_reverse()
  134. local text = "hello luatos!!"
  135. --[[
  136. string.sub,
  137. 从一个字符串中截取指定范围的子字符串
  138. ]]--
  139. -- 截取起始位置7到末尾的子字符串
  140. local sub_str = string.sub(text, 7)
  141. log.info(LOG_TAG, "sub_str", sub_str)
  142. assert(sub_str == "luatos!!")
  143. -- 截取起始位置11到倒数第三位置
  144. local sub_str = string.sub(text, 11, -3)
  145. log.info(LOG_TAG, "sub_str", sub_str)
  146. assert(sub_str == "os")
  147. --[[
  148. string.rep
  149. 字符串重复指定次数(可指定分隔符),返回一个新的字符串
  150. ]]--
  151. local new_str = string.rep("hello", 3)
  152. log.info(LOG_TAG, "new_str", new_str)
  153. assert(new_str == "hellohellohello")
  154. local new_str = string.rep("hello", 3, "!")
  155. log.info(LOG_TAG, "new_str", new_str)
  156. assert(new_str == "hello!hello!hello")
  157. --[[
  158. string.reverse
  159. 返回字符串的反转字符串
  160. ]]--
  161. local new_str = string.reverse("hello*123")
  162. log.info(LOG_TAG, "new_str", new_str)
  163. assert(new_str == "321*olleh")
  164. end
  165. --[[
  166. 用例0105 字符格式化与转换操作
  167. ]]--
  168. function tc0105_str_conversion()
  169. --[[
  170. string.lower
  171. 字符串中的所有字母转换为小写
  172. ]]--
  173. local text1 = string.lower("Hello LuatOS 2025!")
  174. log.info(LOG_TAG, text1)
  175. assert(text1 == "hello luatos 2025!")
  176. --[[
  177. string.upper
  178. 字符串中的所有字母转换为大写
  179. ]]--
  180. local text2 = string.upper("Hello LuatOS 2025!")
  181. log.info(LOG_TAG, text2)
  182. assert(text2 == "HELLO LUATOS 2025!")
  183. --[[
  184. string.char
  185. 接收零或更多的整数,返回和参数数量相同长度的字符串
  186. ]]--
  187. local str = string.char(72, 101, 108, 108, 111)
  188. log.info(LOG_TAG, str)
  189. assert(str == "Hello")
  190. --二进制数据
  191. local bindat = string.char(0, 23, 255, 124, 171)
  192. assert(bindat == "\x00\x17\xFF\x7C\xAB")
  193. --[[
  194. string.byte
  195. 返回字符串指定位置的内部数字编码值
  196. ]]--
  197. -- 获取指定开始结束位置的数值
  198. local dat0,dat1,dat2,dat3,dat4 = string.byte("hello luatos", 6, 10)
  199. log.info(LOG_TAG, dat0,dat1,dat2,dat3,dat4)
  200. assert(dat0==32 and dat1==108 and dat2==117 and dat3==97 and dat4==116)
  201. -- 获取指定位置的一个数值
  202. local dat5 = string.byte("\x01\xAB", 2)
  203. log.info(LOG_TAG, dat5)
  204. assert(dat5 == 171)
  205. --[[
  206. string.format
  207. 格式化字符串并返回新字符串
  208. ]]--
  209. local str1 = '\t\rHello \n2025\\ "Lua"\0' -- "\t\rHello \n2025\\ \"Lua\"\0"
  210. -- %q选项接受一个字符串转化为可安全被 Lua 编译器读入的格式
  211. -- (显式显示几乎所有特殊字符,忽略转义, 返回一个带双引号的新字符串)
  212. local fmt_str = string.format("return str is %q", str1)
  213. log.info(LOG_TAG, fmt_str) -- 返回带双引号的字符串
  214. assert(fmt_str == 'return str is "\\9\\13Hello \\\n2025\\\\ \\"Lua\\"\\0"')
  215. -- %d选项接受一个整型,%s选项接受一个字符串,%f选项接受一个单浮点数(默认6位小数)
  216. fmt_str = string.format("%d,%s,%f",123,"test",1.253)
  217. log.info(LOG_TAG, fmt_str)
  218. assert(fmt_str == "123,test,1.253000")
  219. end
  220. --[[
  221. 用例0106 格式化二进制数据打包与解包
  222. ]]--
  223. function tc0106_str_bin_pack_unpack()
  224. -- 假设按照这个(1, 4, 0xCD56AB12, 0x0A, 0x0104)数据格式打包,
  225. -- 小端格式十六进制表示为:01 00 | 04 00 | 12 AB 56 CD | 0A | 04 01
  226. local test_bin_str = "\x01\x00\x04\x00\x12\xAB\x56\xCD\x0A\x04\x01"
  227. local pack_str = string.pack("<HHI4BH", 1, 4, 0xCD56AB12, 0x0A, 0x0104)
  228. -- 这里也可以使用string.toHex(pack_str) 直接转换成十六进制数据字符串
  229. local fmt_str = string.format("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
  230. pack_str:byte(1),pack_str:byte(2),pack_str:byte(3),pack_str:byte(4),
  231. pack_str:byte(5),pack_str:byte(6),pack_str:byte(7),pack_str:byte(8),
  232. pack_str:byte(9),pack_str:byte(10),pack_str:byte(11))
  233. log.info(LOG_TAG, fmt_str, pack_str:len(), string.packsize("<HHI4BH"))
  234. assert(pack_str == test_bin_str and pack_str:len() == string.packsize("<HHI4BH"))
  235. -- 解包
  236. local dat1,dat2,dat3,dat4,dat5 = string.unpack("<HHI4BH", test_bin_str)
  237. log.info(LOG_TAG, string.format("%X,%X,%04X,%X,%X",dat1,dat2,dat3,dat4,dat5))
  238. assert(dat1 == 1 and dat2 == 4 and dat3 == 0xCD56AB12 and dat4 == 0x0A and dat5 == 0x104)
  239. -- 测试依次打包数值,字符串,浮点数,string.packsize不能用于含s,z的变长选项
  240. -- 选项s6表示把字符串长度保存在6个字节中
  241. pack_str = string.pack("i4s6f", 42, "Lua", 3.14159)
  242. log.info(LOG_TAG, pack_str:len())
  243. -- 可以分次解包,返回已解数据及未解析的开始位置
  244. local data1, pos = string.unpack("i4", pack_str)
  245. -- 可以分次解包,指定下次解析开始位置
  246. local data2, data3 = string.unpack("s6f", pack_str, pos)
  247. log.info(LOG_TAG, string.format("%d,%s,%.5f",data1,data2,data3))
  248. assert(data1 == 42 and data2 == "Lua" and string.format("%.5f",data3) == "3.14159")
  249. end
  250. --[[
  251. 用例0107 字符转换输出操作(扩展API)
  252. ]]--
  253. function tc0107_str_ext_conversion()
  254. --[[
  255. string.toHex
  256. 输入字符串转换,可指定分隔符,返回hex字符串和字符串长度(长度不含分隔符)
  257. ]]--
  258. -- 默认分隔符为"" 空字符串
  259. local text = "Hello Luatos123"
  260. local hex_str, hex_len = string.toHex(text)
  261. log.info(LOG_TAG, text, hex_str, hex_len)
  262. -- 指定分隔符为" " 空格
  263. local data = "\x01\xAA\x02\xFE\x23"
  264. local hex_data, hex_data_len = string.toHex(data, " ")
  265. log.info(LOG_TAG, hex_data, hex_data_len)
  266. local utf8_data = "你好。"
  267. local hex_utf8_data = string.toHex(utf8_data)
  268. log.info(LOG_TAG, hex_utf8_data)
  269. --[[
  270. string.fromHex
  271. 输入hex字符串转换返回字符串,忽略除0-9,a-f,A-F的其他字符
  272. ]]--
  273. local ret_text = string.fromHex(hex_str)
  274. local ret_data = string.fromHex(hex_data)
  275. local ret_utf8_data = string.fromHex(hex_utf8_data)
  276. log.info(LOG_TAG,
  277. ret_text,
  278. string.format("%02X%02X%02X%02X%02X",ret_data:byte(1),ret_data:byte(2),
  279. ret_data:byte(3),ret_data:byte(4),ret_data:byte(5)),
  280. ret_utf8_data)
  281. assert(ret_text == text and ret_data == data and ret_utf8_data == utf8_data)
  282. --[[
  283. string.toValue
  284. 输入返回二进制字符串,及转换的字符数
  285. ]]--
  286. local bin_str,count = string.toValue("123456abc")
  287. log.info(LOG_TAG,
  288. -- 这里也可以使用string.toHex(bin_str) 直接转换成十六进制数据字符串
  289. string.format("%02X%02X%02X%02X%02X%02X%02X%02X%02X",
  290. bin_str:byte(1),bin_str:byte(2),bin_str:byte(3),
  291. bin_str:byte(4),bin_str:byte(5),bin_str:byte(6),
  292. bin_str:byte(7),bin_str:byte(8),bin_str:byte(9)),
  293. count) -- count 为转换的字符数
  294. assert(bin_str == "\x01\x02\x03\x04\x05\x06\x0a\x0b\x0c" and count == 9)
  295. end
  296. --[[
  297. 用例0108 字符编解码-Base64/Base32(扩展API)
  298. ]]--
  299. function tc0108_str_ext_base64_and_base32()
  300. -- 测试普通字符串base64编解码
  301. local text = "Hello"
  302. local base64_str = string.toBase64(text)
  303. log.info(LOG_TAG, base64_str)
  304. local ret_text = string.fromBase64(base64_str)
  305. assert(ret_text == text)
  306. -- 测试二进制数据字符串base64编解码
  307. local data = "\x01\xAB\x34\xFF"
  308. local base64_data = string.toBase64(data)
  309. log.info(LOG_TAG, base64_data)
  310. local ret_data = string.fromBase64(base64_data)
  311. assert(ret_data == data)
  312. -- 测试utf8数据字符串base64编解码
  313. local utf8_data = "你好"
  314. local base64_utf8data = string.toBase64(utf8_data)
  315. log.info(LOG_TAG, base64_utf8data)
  316. local ret_utf8_data = string.fromBase64(base64_utf8data)
  317. assert(utf8_data == utf8_data)
  318. -- 测试普通字符串base32编解码
  319. local text = "Luatos"
  320. local base64_str = string.toBase32(text)
  321. log.info(LOG_TAG, base64_str)
  322. local ret_text = string.fromBase32(base64_str)
  323. assert(ret_text == text)
  324. -- 测试二进制数据字符串base32编解码
  325. local data = "\x01\xAB\x34\xFF"
  326. local base64_data = string.toBase32(data)
  327. log.info(LOG_TAG, base64_data)
  328. local ret_data = string.fromBase32(base64_data)
  329. assert(ret_data == data)
  330. -- 测试utf8数据字符串base32编解码
  331. local utf8_data = "你好"
  332. local base64_utf8data = string.toBase32(utf8_data)
  333. log.info(LOG_TAG, base64_utf8data)
  334. local ret_utf8_data = string.fromBase32(base64_utf8data)
  335. assert(utf8_data == utf8_data)
  336. end
  337. --[[
  338. 用例0109 字符编解码-URL编码(扩展API)
  339. ]]--
  340. function tc0109_str_ext_urlcode()
  341. local text = "Hello world&luat/123*A_B"
  342. -- 第二个参数0:默认参考标准php(可不填),不转换的字符序列".-*_",空格用'+'
  343. local urlencode = string.urlEncode(text)
  344. log.info(LOG_TAG, "defalut php", urlencode)
  345. assert(urlencode == "Hello+world%26luat%2F123*A_B")
  346. -- 第二个参数1:参考rfc3986,不转换的字符序列".-_",空格用'%20'
  347. urlencode = string.urlEncode(text, 1)
  348. log.info(LOG_TAG, "rfc3986", urlencode)
  349. assert(urlencode == "Hello%20world%26luat%2F123%2AA_B")
  350. -- 第二个参数-1:表示自定义, 第三参数0:空格用'+',1:空格用'%20';第四参数指定不用转换的字符序列
  351. urlencode = string.urlEncode(text, -1, 0, "&/ ")
  352. log.info(LOG_TAG, "self defined", urlencode)
  353. assert(urlencode == "Hello world&luat/123%2AA%5FB")
  354. end
  355. --[[
  356. 用例0110 字符串分隔符拆分子字符串(扩展API)
  357. ]]--
  358. function tc0110_str_ext_split()
  359. local text = "/hello,///world,**/luatos//2025*/"
  360. -- 默认分隔符',',默认不保留空白片段
  361. local table1 = string.split(text) -- 这里第二三参数不填使用默认值
  362. log.info(LOG_TAG, #table1, table1[1], table1[2], table1[3])
  363. assert(table1[1] == "/hello" and table1[2] == "///world" and table1[3] == "**/luatos//2025*/")
  364. -- 分隔符'/',保留空白片段,字符串中有连续的分隔符视为分隔两个空字符串,开始和结束有分隔符则分别都有空字符串
  365. local table2 = string.split(text,'/', true)
  366. log.info(LOG_TAG, #table2, json.encode(table2))
  367. assert(table2[1] == "" and table2[2] == "hello," and table2[3] == ""
  368. and table2[4] == "" and table2[5] == "world,**"
  369. and table2[6] == "luatos" and table2[7] == ""
  370. and table2[8] == "2025*" and table2[9] == "")
  371. -- 分隔符'*',保留空白片段,采用':'调用函数,text当作第一个实参传递给函数,等同string.split(text)
  372. local table3 = text:split('*', true)
  373. log.info(LOG_TAG, #table3, json.encode(table3))
  374. assert(table3[1] == "/hello,///world," and table3[2] == "" and table3[3] == "/luatos//2025" and table3[4] == "/")
  375. -- 分隔符'o', 不保留空白片段
  376. local table4 = text:split('o')
  377. log.info(LOG_TAG, #table4, json.encode(table4))
  378. assert(table4[1] == "/hell" and table4[2] == ",///w" and table4[3] == "rld,**/luat" and table4[4] == "s//2025*/")
  379. end
  380. --[[
  381. 用例0111 字符串前后缀判断与操作(扩展API)
  382. ]]--
  383. function tc0111_str_ext_prefix_suffix()
  384. local text = " \tHello LuatOS2025\r\n"
  385. --[[
  386. string.trim
  387. 去除字符串头尾的空白字符包括空格、制表符(\t)、回车(\r)和换行(\n)符
  388. ]]--
  389. -- 第二参数true表示去除前缀(默认true可不填),第三参数true表示去除后缀(默认true可不填)
  390. local ret_str1 = string.trim(text)
  391. log.info(LOG_TAG, #ret_str1, ret_str1)
  392. assert(ret_str1 == "Hello LuatOS2025")
  393. -- 第二参数true表示去除前缀,第三参数false表示保留后缀
  394. local ret_str2 = string.trim(text, true, false)
  395. log.info(LOG_TAG, #ret_str2, ret_str2)
  396. assert(ret_str2 == "Hello LuatOS2025\r\n")
  397. --[[
  398. string.startsWith
  399. 判断字符串前缀,匹配前缀返回true
  400. ]]--
  401. local rc = string.startsWith(ret_str1, "He")
  402. log.info(LOG_TAG, "startwith \"He\", rc=", rc)
  403. assert(rc)
  404. rc = string.startsWith(text, " \t")
  405. log.info(LOG_TAG, "startwith \" \\t\", rc=", rc)
  406. assert(rc)
  407. --[[
  408. string.endsWith
  409. 判断字符串后缀,匹配后缀返回true
  410. ]]--
  411. rc = string.endsWith(ret_str1, "25")
  412. log.info(LOG_TAG, "endwith \"25\",rc=", rc)
  413. assert(rc)
  414. rc = string.endsWith(text, "\r\n")
  415. log.info(LOG_TAG, "endwith \"\\r\\n\",rc=", rc)
  416. assert(rc)
  417. end
  418. --[[
  419. 用例0201 测试空字符串参数(仅测试扩展API接口)
  420. ]]--
  421. function tc0201_str_ext_nullstr_param()
  422. local ret_str, ret_len = string.toHex("")
  423. log.info(LOG_TAG,"toHex:", ret_str, ret_len)
  424. assert(ret_str == "")
  425. ret_str = string.fromHex("")
  426. log.info(LOG_TAG,"fromHex:", ret_str)
  427. assert(ret_str == "")
  428. ret_str,ret_len = string.toValue("")
  429. log.info(LOG_TAG,"toValue:", ret_str, ret_len)
  430. assert(ret_str == "")
  431. ret_str = string.toBase64("")
  432. log.info(LOG_TAG,"toBase64:", ret_str)
  433. assert(ret_str == "")
  434. ret_str = string.fromBase64("")
  435. log.info(LOG_TAG,"fromBase64:", ret_str)
  436. assert(ret_str == "")
  437. ret_str = string.toBase32("")
  438. log.info(LOG_TAG,"toBase32:", ret_str)
  439. assert(ret_str == "")
  440. ret_str = string.fromBase32("")
  441. log.info(LOG_TAG,"fromBase32:", ret_str)
  442. assert(ret_str == "")
  443. ret_str = string.urlEncode("")
  444. log.info(LOG_TAG,"urlEncode:", ret_str)
  445. assert(ret_str == "")
  446. local ret_tab = string.split("")
  447. log.info(LOG_TAG,"split:", ret_tab)
  448. assert(type(ret_tab) == "table" and #ret_tab == 0)
  449. local rc = string.startsWith("","")
  450. log.info(LOG_TAG,"startsWith:", rc)
  451. assert(rc == true)
  452. rc = string.endsWith("","")
  453. log.info(LOG_TAG,"endsWith:", rc)
  454. assert(rc == true)
  455. ret_str = string.trim("")
  456. log.info(LOG_TAG,"trim:", ret_str)
  457. assert(ret_str == "")
  458. end
  459. --[[
  460. 用例0202 测试异常范围参数(扩展API接口)
  461. ]]--
  462. function tc0202_str_ext_over_range_param()
  463. -- 字符处理方法:char >'9'则(char+9)&0x0f, 否则char&0x0f
  464. local ret_str,ret_len = string.toValue("1qWe")
  465. log.info(LOG_TAG,
  466. string.format("%02X%02X%02X%02X",
  467. ret_str:byte(1),ret_str:byte(2),ret_str:byte(3),ret_str:byte(4)),
  468. ret_len)
  469. assert(ret_str == "\x01\x0A\x00\x0E")
  470. ret_str,ret_len = string.toValue(" \r\n")
  471. log.info(LOG_TAG,
  472. string.format("%02X%02X%02X",
  473. ret_str:byte(1),ret_str:byte(2),ret_str:byte(3)),
  474. ret_len)
  475. assert(ret_str == "\x00\x0D\x0A")
  476. -- 指定异常前后缀的判断比较
  477. local rc = string.startsWith("hello","12")
  478. log.info(LOG_TAG,"startsWith:", rc)
  479. assert(rc == false)
  480. rc = string.startsWith("hello","hello1")
  481. log.info(LOG_TAG,"startsWith:", rc)
  482. assert(rc == false)
  483. rc = string.startsWith("hello","\0")
  484. log.info(LOG_TAG,"startsWith:", rc)
  485. assert(rc == false)
  486. rc = string.startsWith("hello","")
  487. log.info(LOG_TAG,"startsWith:", rc)
  488. assert(rc == true)
  489. rc = string.endsWith("hello","hello")
  490. log.info(LOG_TAG,"endsWith:", rc)
  491. assert(rc == true)
  492. rc = string.endsWith("hello","")
  493. log.info(LOG_TAG,"endsWith:", rc)
  494. assert(rc == true)
  495. end
  496. --[[
  497. 用例0203 测试异常范围Base64或Base32参数(扩展API接口)
  498. ]]--
  499. function tc0203_str_ext_base64_base32_illegal_param()
  500. -- Base64/Base32解码测试自动补全填充符'='
  501. -- 不支持补全填充符?不检查长度?
  502. local encoded = "SGVsbG8" -- 缺少填充符
  503. local decoded = string.fromBase64(encoded)
  504. log.info(LOG_TAG,"decoded:", decoded)
  505. assert(decoded == "Hel", "Base64 decode fail")
  506. encoded = "JR2WC5DPOM" -- 缺少填充符
  507. decoded = string.fromBase32(encoded)
  508. log.info(LOG_TAG,"decoded:", decoded)
  509. assert(decoded == "Luatos", "Base32 decode fail")
  510. -- Base64/Base32解码测试异常字符参数
  511. encoded = "SGsb*G8!" -- 非法字符
  512. decoded = string.fromBase64(encoded)
  513. log.info(LOG_TAG,"decoded:", decoded)
  514. -- 解码失败应该返回空字符串
  515. assert(decoded == "", "Base64 igllegal param")
  516. encoded = "JR2W*08C5DP!" -- 非法字符
  517. decoded = string.fromBase32(encoded)
  518. log.info(LOG_TAG,"decoded:", decoded)
  519. -- 解码失败应该返回空字符串
  520. assert(decoded == "", "Base32 igllegal param")
  521. end
  522. -- 测试用例的table,以函数名为键,函数为值,实际运行无序可以增加测试的随机性
  523. -- string的测试函数集
  524. local str_test_suite = {
  525. --[[
  526. 接口功能测试
  527. ]]--
  528. ["tc0101_str_base_operation"] = tc0101_str_base_operation,
  529. ["tc0102_str_pattern_matching"] = tc0102_str_pattern_matching,
  530. ["tc0103_str_replace"] = tc0103_str_replace,
  531. ["tc0104_str_truncate_copy_reverse"] = tc0104_str_truncate_copy_reverse,
  532. ["tc0105_str_conversion"] = tc0105_str_conversion,
  533. ["tc0106_str_bin_pack_unpack"] = tc0106_str_bin_pack_unpack,
  534. ["tc0107_str_ext_conversion"] = tc0107_str_ext_conversion,
  535. ["tc0108_str_ext_base64_and_base32"] = tc0108_str_ext_base64_and_base32,
  536. ["tc0109_str_ext_urlcode"] = tc0109_str_ext_urlcode,
  537. ["tc0110_str_ext_split"] = tc0110_str_ext_split,
  538. ["tc0111_str_ext_prefix_suffix"] = tc0111_str_ext_prefix_suffix,
  539. --[[
  540. 异常与边界测试
  541. ]]--
  542. ["tc0201_str_ext_nullstr_param"] = tc0201_str_ext_nullstr_param,
  543. ["tc0202_str_ext_over_range_param"] = tc0202_str_ext_over_range_param,
  544. ["tc0203_str_ext_base64_base32_illegal_param"] = tc0203_str_ext_base64_base32_illegal_param,
  545. }
  546. -- test_run函数接受一个table参数,table中包含测试用例函数
  547. -- 调用了sys.wait()需要在任务中调用
  548. function test_run(test_cases)
  549. local successCount = 0 -- 成功的测试用例计数
  550. local failureCount = 0 -- 失败的测试用例计数
  551. -- 遍历table中的每个测试用例函数
  552. for name, testCase in pairs(test_cases) do
  553. -- 检查testCase是否为函数
  554. if type(testCase) == "function" then
  555. -- 使用pcall来捕获测试用例执行中的错误, 若有错误也继续往下执行
  556. local success, err = pcall(testCase)
  557. if success then
  558. -- 测试成功,增加成功计数
  559. successCount = successCount + 1
  560. log.info(LOG_TAG, "Test case passed: " .. name)
  561. else
  562. -- 测试失败,增加失败计数
  563. failureCount = failureCount + 1
  564. log.info(LOG_TAG, "Test case failed: " .. name .. " - Error: " .. err)
  565. end
  566. else
  567. log.info(LOG_TAG, "Skipping non-function entry: " .. name)
  568. end
  569. -- 稍等一会在继续测试
  570. sys.wait(1000)
  571. end
  572. -- 打印测试结果
  573. log.info(LOG_TAG, "Test run complete - Success: " .. successCount .. ", Failures: " .. failureCount)
  574. end
  575. -- 定义任务来开始demo测试流程
  576. sys.taskInit(function()
  577. -- 为了显示日志,这里特意延迟一秒
  578. -- 正常使用不需要delay
  579. sys.wait(1000)
  580. -- 运行测试套件
  581. test_run(str_test_suite)
  582. end)
  583. -- 用户代码已结束---------------------------------------------
  584. -- 结尾总是这一句
  585. sys.run()
  586. -- sys.run()之后后面不要加任何语句!!!!!