code repo connnect test
[shlib.git] / bin / codegen
blobda8ff9aa1bae7e927b45897061d08689080c1cfc
1 #!/bin/bash
2 ############################################################
3 # source: codegen
4 # author: devenkong(18151155@qq.com)
5 # date: 2023-05-07
6 ############################################################
7 # Copyright (C) 2022- Free Software Foundation, Inc.
8 # This configure script is free software; the Free Software
9 # Foundation gives unlimited permission to copy, distribute
10 # and modify it.
11 ############################################################
12 # note:
14 ############################################################
16 # Testing:
17 # @
20 asdfas='
21 -O , --output-dir=<output_dir> 指定测试时的临时文件目录。默认值为~/用户目录下的
22 .testing目录。
23 -f , --force 指定测试信息的目录。默认值为当前目录下的testing
24 目录。
25 -y , --sync 根据测试信息描述文件,生成测试目录及测试脚本等文
26 =[sync_to_dir] 件,用于用户编写各种测试用例。
27 # todo:输出文件目录异常。暂时disable该功能。
28 # tbd:使用同步输出为-g参数,-y用于sync-back
33 # todo:
39 . shlibinc
41 include stdio.shlib
42 include dbgout.shlib
43 include term.shlib
44 include args.shlib
45 include gplib.shlib
47 include cataid.shlib
48 include dirgen.shlib
50 #include strsyntax.shlib
51 #include attr.shlib
52 include catalog.shlib
54 #dsource imifile.shlib
57 #loadini codegen.ini
58 #loadimi codegen.imi
60 #include param/param.shlib
62 ##############################
63 # section: public comment info
64 ##############################
68 ##############################
69 # section: variable define
70 ##############################
73 UNIT_TEST_MS=
77 TESTING_ROOT_DIR=
78 # XXX:
79 TESTING_TMP_DIR=~/.testing/$(basename $0)/
81 # XXX:
82 test_cnt=0
83 test_cnt_num=99999
85 # XXX:
86 err_continue_cnt=0
87 err_cnt=0
89 # XXX:
90 FCCOLOR=$FCGREEN
91 IFCCOLOR=$FCMAGENTA
92 EFCCOLOR=$FCRED
93 INFOCOLOR=$FCGREEN
95 # XXX:
96 readonly FCR2L="${FCCYAN}"
97 readonly FCL2R="${FCCYAN}${CREV}"
98 verbos_pfx=" ${INFOCOLOR}+$CNORMAL "
101 # do not delete this comment, it is used for var define code intert.
103 # args-var-define-begin
104 # args-var-define-end
108 # desc-str for codegen
109 # @ every paramter desc-str-line start with 'param'.
110 # @ every colum start with '|', and seperated by blanks.
111 # @ '|blank' means a blank line dispalyed in helper.
112 # @ follow with a '' quoated string is the option category string.
113 # @ comment '#' in desc-str is also supported, and can be used to
114 # disable some option have not been implemented.
115 # @ desc-str can be in multiple var. and some of them maybe re-used
116 # for other program by 'source xxx --loadshlib'.
118 codegen_desc_str="
119 |prog $0 '应用测试程序。用于对指定目录下的一系列测试脚本运行测试,并输出测试结果。如未指定测试目录参数,以当前目录下的testing目录作为默认测试信息目录,并进行测试。'
121 |blank 'Design File Auto Gen Paramters:'
122 |param |-l |--list |--- |= |%<list_test_list> |&<args_list_item> |'list items and dirs under testing dir.'
123 |param |-S |--save |--- |=<save_desc_file> |%<save_desc_file> |&<args_save_catalog> |'generate catalog from testing dir. if the catalog file is exist, just display desc info only. append -f option to recover an original catalog file. '
124 # -y参数存在bug,不添加到程序功能中。
125 |param |-y |--sync |--- |=[sync_to_dir] |%<sync_to_dir> |&<args_sync_to_dir> |'generate 根据测试信息描述文件,生成测试目录及测试脚本等文件,用于用户编写各种测试用例。'
126 |blank
128 |blank 'Testing Output Info Paramters:'
129 |param |-u |--update |--- |= |%<update_test_file> |& |'if the current test item is ok, save stdout output to test item as the standard output content.'
130 |param |-v |--verbose |--- |= |%<verbose> |&<args_verbose> |'output the test script outputed with \'+ \' prefix. it is the detail output info for testing.'
131 |param |-q |--quiet |--- |= |%<quiet> |& |'disable comparation string output. but it is not conflect with -v option. use -v -q means output detail string info instead of comparation string.'
132 |blank
134 |blank 'Misc Paramters:'
135 |param |-f |--force |--- |= |%<test_force> |& |'force operation option. it\'s a general option combine with other options.'
136 |param |-j |--multi-task |--- |=<multi_task> |%<multi_task> |& |'multi-task running. set the parall num of tasks.'
137 |param |-M |--matching |--- |=<matching> |%<matching> |&<args_matching> |'string matching test, and generate chksum.'
138 |blank
141 another_desc_str="
142 |blank 'Other Paramters:'
143 |param |-d |--dir |--- |=<test_dir> |%<test_dir> |& |'指定测试信息的目录。默认值为当前目录下的testing目录。'
144 |param |-O |--output-dir |--- |=<output_dir> |%<output_dir> |& |'指定测试时的临时文件目录。默认值为~/用户目录下的.testing目录。'
145 |param |-p |--print-vars |--- |= |%<print_vars> |&<args_print_vars> |'输出参数定义的变量信息。'
146 |param |-m |--mono |--- |= |%<mono> |&<args_mono> |'输出非彩色的字符串信息。'
147 |param |-g |--logfile |--- |= |%<test_logfile> |&<test_logfile> |'测试failed时,不输出差异信息。'
148 |blank
150 |blank 'Version & Helper & Debug:'
151 |param |-V |--version |--- |= |%<version_info> |&<args_version> |'output version info of the program.'
152 |param |-h |-- |--- |= |%<h_info> |&<args_h_info> |'simplly helper doc only for option.'
153 |param |- |--help |--- |= |%<help_info> |&<args_help_info> |'this helper doc.'
154 |param |- |--debug |--- |= |%<test_debug> |&<args_test_debug> |'debug info for arguments dispatch. add the option follow with cmd.'
158 readonly PROG=`basename $0`
161 # this comment is used for version id auto update.
163 # @{prog-ver-begin}
164 readonly V1=0
165 readonly V2=1
166 readonly V3=0
167 readonly VEXT=
168 readonly VER_DATE=20230501
169 # @{prog-ver-end}
171 readonly eval_PROG_VERSION="v${V1}.${V2}\${V3:+\".$V3\"}\${VEXT:+\"$VEXT\"}\${VER_DATE:+\"-$VER_DATE\"}"
172 PROG_VERSION="`eval echo $eval_PROG_VERSION`
173 Copyright (C) 2023- Free Software Foundation, Inc.
174 This configure script is free software; the Free Software
175 Foundation gives unlimited permission to copy, distribute
176 and modify it.
178 Writen by deven(devenkong@126.com).
181 PROG_BANNER="$PROG $PROG_VERSION"
182 PROG_SYNTAX="Usage: $PROG -[lS:n:LFrat:b:e:x:RBscuvd:O:qpmVhfj:g]"
183 PROG_DESC=" this program is an automatical code generating utility.
184 # XXX:
188 this program is a test-suite program to orgnize a lot of test item script. as a direct structure on file system, and execute them. when testing error,it show differece betwin current output content and the correct output content, which saved in the item files.
189 this prog can be used as a unit testing tool, and also can be used as a functional testing tool, to running the program (set) testing before installization, and check if it can be running in current enviroument.
190 i use this util to execute loop-back testing that i tested before. it will save time to test some repeated problem in detail. if i write a new feature for a program, i will check if the new code would make original code error.
191 some of the option description is writen by chinese char, it is used to test utf-8 char dispaly when it works in words bundary truncate feature.
194 PROG_OTHER_DESC="
195 EXAMPLES:
197 @ code generating and synchronizing:
199 codegen -y
200 s[y]nchronize code to output dir.
202 @ list catalog node:
204 codegen -l
205 list catalog structure in testdir.
207 codegen -S
208 save catalog node info into .catalog file.
212 codegen -
217 codegen_fmt_usage="$PROG_BANNER
218 @{PROG_SYNTAX}
219 $PROG_DESC
220 @{helper}
221 $PROG_OTHER_DESC
225 ##############################
226 # section: private function
227 ##############################
230 ############################################################################
232 ############################################################################
235 # fsyntax: testing_paths_init [<base-tmp-dir>]
236 # fdesc:
237 testing_paths_init ()
240 # 测试目录使用-d参数对应的test_dir环境变量
241 # 指定的目录作为测试信息目录。
242 # 默认为当前路径下的testing目录。
244 if [[ -n $test_dir ]]; then
245 if [[ -d $test_dir ]]; then
246 test_path=$test_dir
247 else
248 err "err: parameter -d specified a invalid path $test_dir\n"
249 exit
253 SRCPKG_DIR="$(pwd)"
254 TEST_DIR_STR_FMT="$(attr_get catalog::testdir::STR_FMT)"
255 TEST_SUBJECT_DIR="$SRCPKG_DIR/$(attr_get catalog::testdir::SUBJECTDIR)"
257 if [[ ! -d $test_path ]]; then
258 test_path=testing/
261 [[ ! -d $test_path ]] && err "err: testcase dir is not exist.\n" && exit
263 mkdir -p "$test_path"
264 cd "$test_path"
265 test_path=$PWD
266 cd - > /dev/null
269 # 测试的tmp目录设置
270 # 目录名称添加testcase路径的cksum,避免同一个软件包不同目录时,
271 # 使用同一个tmp目录。
273 TESTING_TMP_DIR=$(basename $0)-$TESTING_TMP_DIR
274 if [[ -n $1 ]]; then
275 TESTING_TMP_DIR="$1/"
276 [[ -d $1 ]] && TESTING_TMP_DIR=~/.testing/ && warn "directoy specified \"$1\" is not existing, use default directrory \"$TESTING_TMP_DIR\" instead.\n"
277 else
278 TESTING_TMP_DIR=~/.testing/
281 mkdir -p "$TESTING_TMP_DIR"
282 cd "$TESTING_TMP_DIR"
283 TESTING_TMP_DIR=$PWD
284 cd - > /dev/null
286 TESTING_TMP_DIR=$TESTING_TMP_DIR/$(basename $0)-$(echo $test_path | cksum - | cut -d ' ' -f1)
288 mkdir -p "$TESTING_TMP_DIR"
292 # fsyntax: testing_catalog_id_init
293 # fdesc: range id init is a general feature programs. this function can be used in
294 # other programs.
296 testing_catalog_id_init ()
298 local tmp
300 cataid_create TEST
302 # load保存的id参数
303 local tmp_exclude_id="$exclude_id"
304 local tmp_begin_test_id="$begin_test_id"
305 local tmp_end_test_id="$end_test_id"
307 [[ -e $TESTING_TMP_DIR/test_id.txt ]] && source $TESTING_TMP_DIR/test_id.txt
308 [[ -n $tmp_exclude_id && $tmp_exclude_id =~ [^\ ] ]] && exclude_id="$tmp_exclude_id"
309 [[ -n $tmp_begin_test_id ]] && begin_test_id="$tmp_begin_test_id"
310 [[ -n $tmp_end_test_id ]] && end_test_id="$tmp_end_test_id"
311 unset tmp_exclude_id
312 unset tmp_begin_test_id
313 unset tmp_end_test_id
316 # 测试id起止范围和状态的初始化
317 # 以testing目录中保存的起止id、参数设置、failed测试项的
318 # 顺序设置id值。
320 if [[ $failed_begin == "enable" && -f $TESTING_TMP_DIR/testing_failed_list.txt ]]; then
321 tmp=$(head -n 1 $TESTING_TMP_DIR/testing_failed_list.txt)
322 [[ -n $tmp ]] && begin_test_id=$tmp
325 if [[ $test_all == "enable" ]]; then
326 exclude_id=""
327 test_cnt_num=
328 # test_ignor_err="enable"
329 else
330 exclude_id=$(echo "${exclude_id}" | tr ' ' '\n' | sort - | uniq)
331 exclude_id=" $(echo "${exclude_id}" | tr "$'\n'" ' ') "
334 # inner
335 catalog_id_set_init_state TEST "inner"
336 if [[ -n $end_test_id ]]; then
337 catalog_id_set_end_id TEST end_test_id
340 if [[ -n $begin_test_id ]]; then
341 catalog_id_set_begin_id TEST begin_test_id
343 # 如果有begin-id,默认起始状态为 lower
344 catalog_id_set_init_state TEST "lower"
347 # dbgoutd "TEST_CID_STATE=${TEST_CID_STATE[@]}\n"
348 # dbgoutd "TEST_CID_BEGIN=${TEST_CID_BEGIN[@]}\n"
349 # dbgoutd "TEST_CID_END=${TEST_CID_END[@]}\n"
351 if [[ $test_all == "enable" ]]; then
352 begin_test_id=""
353 end_test_id=""
355 catalog_id_set_begin_id TEST begin_test_id
356 catalog_id_set_end_id TEST end_test_id
358 # 如果有begin-id,默认起始状态为 lower
359 catalog_id_set_init_state TEST "inner"
362 # id起止范围有效性判断
363 catalog_id_begin_end_chk TEST
365 # 测试起始范围递增1
366 if [[ $test_id_rollup == "enable" ]]; then
367 [[ -z $begin_test_id ]] && echo "请使用-b参数指定起始测试编号" && exit
369 catalog_id_rollup_in_dir TEST begin_test_id $test_path
370 ret=$?
371 [[ $ret != 0 ]] && exit
373 begin_test_id=${TEST_CID_BEGIN[@]}
374 begin_test_id=${begin_test_id// /.}
375 set_test_info="enable"
378 # 测试起始范围回退1
379 if [[ $test_id_rollback == "enable" ]]; then
380 [[ -z $begin_test_id ]] && echo "请使用-b参数指定起始测试编号" && exit
382 catalog_id_rollback_in_dir TEST begin_test_id $test_path
383 [[ $? != 0 ]] && exit
385 begin_test_id=${TEST_CID_BEGIN[@]}
386 begin_test_id=${begin_test_id// /.}
387 set_test_info="enable"
390 # 保存-b -e参数指定的id
391 if [[ $set_test_info == "enable" ]]; then
392 [[ -z $begin_test_id && -z $end_test_id && -z $exclude_id && ! $exclude_id =~ [^\ ] ]] && echo "请使用-x-b-e参数指定起止测试编号和exclude-id" && exit
394 info "begin test_id: ${begin_test_id[@]}\n"
395 info "end test_id: ${end_test_id[@]}\n"
396 info "exclude test_id: '$exclude_id'\n"
398 # 保存参数
399 mkdir -p "$TESTING_TMP_DIR"
400 echo "# [paramters]" > $TESTING_TMP_DIR/test_id.txt
401 [[ -n $begin_test_id ]] && echo "begin_test_id=${begin_test_id}" >> $TESTING_TMP_DIR/test_id.txt
402 [[ -n $end_test_id ]] && echo "end_test_id=${end_test_id}" >> $TESTING_TMP_DIR/test_id.txt
403 [[ -n $exclude_id && $exclude_id =~ [^\ ] ]] && echo "exclude_id='`echo ${exclude_id}`'" >> $TESTING_TMP_DIR/test_id.txt
405 info "test id saved!\n"
407 # 测试id保存时,不进行测试,便于testcase中测试起止id编号
408 exit
411 # dispaly test id range.
412 if [[ -n ${begin_test_id[@]} || -n ${end_test_id[@]} ]]; then
413 info "Test from <${begin_test_id[@]}> to <${end_test_id[@]}>.\n"
414 [[ -n $exclude_id ]] && info "Except: ${exclude_id}\n"
415 else
416 info "Full item testing.\n"
417 [[ $exclude_id =~ [^\ ] ]] && info "Except: ${exclude_id}\n"
419 [[ -n ${test_cnt_num} ]] && info "Test item count: ${test_cnt_num}\n"
423 # option action function list.
429 args_list_item ()
431 include param/param.shlib
433 # Init Testing Path
434 testing_paths_init
436 if [[ $test_force == "enable" ]]; then
437 test_list_full_content $test_path
438 else
439 test_list_full_content $test_path | more
442 exit
447 args_save_catalog ()
449 info "generate catalog from testing dir!\n"
451 [[ -z $1 ]] && return
453 test_force="enable"
454 args_list_item > $1
456 exit
460 # 描述文件中第一个有效行的空格数或tab数为缩进字符串的单位,用于计算目录层数。
461 # tabh空格不能混用。
463 args_sync_to_dir ()
465 local tmp="$1"
466 local path
468 info "generate testing dir framework from catalog!\n"
470 [[ -z $tmp || ! -f $tmp ]] && tmp=$3
472 # 初始化测试目录
473 testing_paths_init
475 [[ ! -f $tmp ]] && tmp="$test_path/${DEF_TESTING_CATALOG}"
476 [[ ! -f $tmp ]] && err "err: file ($tmp) does not exist.\n" && exit
478 path=$(basename $tmp)
479 tmp=$(dirname $tmp)
480 cd "$tmp"
481 path=$(pwd)/$path
482 cd - 2>/dev/null
485 # todo:
486 # 比较已有的testcase目录与func_list,对差异部分进行更新。
488 catalog_content_cmp $path
489 output_dir_cmp $path
490 testcase_framework_gen_new $path
492 exit
496 # 测试运脚本输出信息的显示。
497 args_verbose ()
499 IFCCOLOR="$FCBLUE"
504 args_matching ()
506 include param/catanode.shlib
508 echo "'$@' matching='$matching'"
510 #NCATAID_REGEX="([[:xdigit:]-]*)"
511 NCATAID_REGEX="(.*)"
512 NNAME_REGEX="([[:alnum:]_]*)"
513 #NDESC_REGEX="([[:alnum:]_-+[:blank:]]*)"
514 NDESC_REGEX="([^\.\"]*)"
515 NODE_TYPE_REGEX="([[:alnum:]_]*)"
517 STR_FMT="$(attr_get catalog::catanode::STR_FMT)"
518 PAIRCHARS="$(attr_get catalog::catanode::PAIRCHARS)"
519 str2var @matching
520 ITEM_CHKSUM="$(echo "$NTYPE $NNAME $NDESC" | cksum)"
521 ITEM_CHKSUM="${ITEM_CHKSUM:0:6}"
522 declare -p NCATAID_REGEX STR_FMT NCATAID NTYPE NNAME NDESC ITEM_CHKSUM
524 exit
528 # 输出程序中的变量信息。
530 args_print_vars ()
532 info "printf vars in codegen!\n"
534 OptDescParamPrint
536 exit
540 # 输出信息单色显示。
541 # args_mono
542 args_mono ()
544 FCCOLOR=""
545 IFCCOLOR=""
546 EFCCOLOR=""
550 # 显示版本信息。
551 # args_version
552 args_version ()
554 echo "$PROG_VERSION"
556 exit
561 args_h_info ()
563 echo -ne "Options:\n"
564 opt_helper
565 echo -ne "\nuse '$PROG --help' for more details.\n"
566 exit
570 # args_help_info
571 args_help_info ()
573 [[ -z $term_width ]] && term_width=80
575 echo -ne "${PROG_SYNTAX}\n\n"
576 echo -ne "$PROG_BANNER\n"
577 echo -ne "$PROG_DESC\n" | fold -b -s -w $term_width - 2>/dev/null
578 echo -ne "\nOptions:\n"
579 opt_helper
580 echo -ne "$PROG_OTHER_DESC"
582 exit
586 # 显示调试信息,这里显示desc-str解析和参数解析后的环境变量信息。
588 args_test_debug ()
594 # main function
597 main ()
600 # program arguments resolve.
601 # it invoke opt_desc_str_dispatch and prog_opt_proc seperatly,
602 # instead of prog_opt_dispatch, for multiple desc-str.
603 # 测试起止范围id的初始化
604 # 初始化测试的tmp目录路径,设置testcase的目录
606 # prog_opt_dispatch "$@"
607 opt_desc_str_dispatch codegen_desc_str
608 opt_desc_str_dispatch another_desc_str
609 prog_opt_proc "$@"
611 # todo:
612 # ini文件加载环境变量
614 init_dbglogout 2 testing 20000
615 # set_output_prefix info ""
616 set_auto_newline ""
619 # running action list function for options after init.
620 # the paramter for init will be effact, then execute the
621 # action function.
623 action_list_exec
625 testing_paths_init $output_dir
626 if [[ $clean == "enable" ]]; then
627 info "re-init tmp dir.\n"
628 rm "$TESTING_TMP_DIR" -rf
629 exit
632 # 使用测试目录中的begin-id和end-id
633 catalog_id_init TEST
634 testing_catalog_id_init
637 # test the specified dir.
639 info "begin testing ... \n"
640 test_unit "$test_path"
641 if [[ -e $TESTING_TMP_DIR/testing_failed_list.txt ]]; then
642 cat $TESTING_TMP_DIR/testing_failed_list.txt | sort -n | uniq > ~/testing_failed_list.txt
643 mv ~/testing_failed_list.txt $TESTING_TMP_DIR/testing_failed_list.txt
645 info "end testing ...\n"
648 # testing result info
650 test_result_info
653 ##############################
654 # section: public function
655 ##############################
659 # fdesc: the wrap of main(), and it append init code of some feature.
661 ExeMain ()
663 if [[ "$@" =~ "--debug" ]]; then
664 declare -g DBGOUTD_OUTPUT=1
666 # does not need to shift args if the --debug option is not the
667 # first option. it will be ignore in process.
668 # shift
671 if [[ $1 != "--loadshlib" ]]; then
672 main "$@"
673 else
674 shift
678 ExeMain "$@"
679 unset DBGOUTD_OUTPUT
681 ##############################
682 # section: file tail
683 ##############################
691 asdfkls="
692 |blank 'General Testing Paramters:'
693 |param |-n |--num |--- |=<test_cnt_num> |%<test_cnt_num> |& |'running N test items continously.'
694 |param |-L |--failed-begin |--- |= |%<failed_begin> |& |'从failed列表中的第一项开始测试。'
695 |param |-F |--failed |--- |= |%<failed_test> |&<args_failed_test> |'test the failed items listed by -a option. it\x27s equal to -L -r -q option.'
696 |param |-r |--ignor-err |--- |= |%<test_ignor_err> |& |'ignor testing error, and running continously.'
697 |param |-a |--all |---all |= |%<test_all> |& |'test for all.'
698 |param |-A |-- |--- |= |%<continouse_all> |&<args_all> |'test for all with -r -q option.'
699 |blank
701 |blank 'Testing Range Paramters:'
702 |param |-t |--test |--- |=<test_id> |%<test_id> |&<args_test_id> |'test a specified item by test item id.'
703 |'the id can be a dir id, that means test the items under the dir. if no id specified, it will test from the beginning id of normal testing.'
704 |param |-b |--begin |--- |=<begin_test_id> |%<begin_test_id> |& |'begin id of testing range.'
705 |param |-e |--end |--- |=<end_test_id> |%<end_test_id> |& |'end id of the testing range.'
706 |param |-x |--exclude |--- |=<exclude_id> |%<exclude_id> |&<args_exclude> |'exclude id that should not be tested.'
707 |param |-R |--rollup |--- |= |%<test_id_rollup> |& |'rollup begin id, if the corresponding item is ok.'
708 |param |-B |--rollback |--- |= |%<test_id_rollback> |& |'rollback begin id to the previous value. it is not simplly decrease the count of id, it will check the test item file first.'
709 |param |-s |--set |--- |= |%<set_test_info> |& |'save the range setted by -b and -e and -x option.'
710 |param |-c |--clean |--- |= |%<clean> |&<args_clean> |'clean testing temp dir.'
711 |blank
715 test_result_info ()
717 if [[ $err_cnt != 0 ]]; then
718 info "$EFCCOLOR($FCGREEN$test_cnt$EFCCOLOR) items is tested,Error count is ($FCGREEN$err_cnt$EFCCOLOR)$CNORMAL\n"
719 else
720 info "$FCGREEN($test_cnt) items is tested,Error count is ($err_cnt)$CNORMAL\n"
725 # todo:-F参数的-n未添加,以及err_cnt信息
726 args_failed_test ()
728 local test_id
729 local id
730 local i
731 local cnt
732 local tmp
733 local curr_path=$PWD
734 local ret
736 catalog_id_set_begin_id TEST ""
737 catalog_id_set_end_id TEST ""
738 # begin_test_id=""
739 # end_test_id=""
741 # 初始化测试目录
742 testing_paths_init
743 catalog_id_init TEST
745 info "failed item testing!\n"
747 # dbgout_cmd cat $TESTING_TMP_DIR/testing_failed_list.txt
749 [[ ! -f $TESTING_TMP_DIR/testing_failed_list.txt ]] && warn "testing failed recode is not exist.\n" && exit
751 while read test_id; do
752 [[ -z $test_id ]] && continue
753 args_test_id $test_id "continue"
754 ret=$?
755 if [[ $test_ignor_err != "enable" ]]; then
756 err "err interrupt ...\n"
757 break
759 continue
760 done < $TESTING_TMP_DIR/testing_failed_list.txt
762 if [[ -e $TESTING_TMP_DIR/testing_failed_list.txt ]]; then
763 cat $TESTING_TMP_DIR/testing_failed_list.txt | sort -n | uniq > ~/testing_failed_list.txt
764 mv ~/testing_failed_list.txt $TESTING_TMP_DIR/testing_failed_list.txt
767 exit
773 args_all ()
775 declare -g -x test_all="enable"
776 declare -g -x test_ignor_err="enable"
777 declare -g -x quiet="enable"
782 args_test_id ()
784 local test_id
785 local id
786 local i
787 local cnt
788 local tmp
789 local curr_path=$PWD
790 local ret
792 catalog_id_set_begin_id TEST ""
793 catalog_id_set_end_id TEST ""
794 # begin_test_id=""
795 # end_test_id=""
797 # 初始化测试目录
798 testing_paths_init
799 catalog_id_init TEST
801 test_id=$1
802 [[ ! ( -n $2 && "$2" == "continue" ) ]] && info "test specified item($test_id).!\n"
804 [[ "$1" =~ [^0-9.] ]] && test_id=$3
805 [[ "$test_id" =~ [^0-9.] ]] && err "test id($test_id) is not correct.\n" && exit
807 OLD_IFS=$IFS
808 IFS="."
809 test_id=( $test_id )
810 cnt=${#test_id[@]}
811 IFS=$OLD_IFS
813 cd "$test_path"
814 IFS=$'\n'
815 for (( i=0; i<cnt; i++ )); do
816 [[ -z ${test_id[$i]} ]] && err "err: test_id[$i] does not invalid.\n" && exit
817 id=${test_id[$i]}
818 tmp="`find $id.* -maxdepth 1 -type d 2>/dev/null`"
819 tmp=( $tmp )
821 if [[ -d $tmp ]]; then
822 cd "$tmp"
823 tmp=""
824 catalog_id_step_into TEST "$id"
825 continue
827 tmp=( `ls -1 "$id".*.sh 2>/dev/null` )
829 [[ -e ${tmp[0]} ]] && break
830 warn "test id '$1' is not a valid id.\n"
831 exit
832 done
833 IFS=$OLD_IFS
835 # use the script code to retest for loop back testing.
836 if [[ $i == $cnt ]]; then
837 test_unit .
838 ret=$?
839 test_result_info
841 [[ -z $2 || "$2" == "continue" ]] && exit
843 return $ret
846 # todo:这里可以改为测试一个unit
847 [[ -z $tmp ]] && err "err: test id ($1) does not specify a valide test item file.\n" && exit
849 tmp=`ls -d "$id".*.txt`
850 [[ -z $tmp ]] && err "err: test id ($i) does not contain a corresponding txt description file.\n" && exit
852 OLD_IFS=$IFS
853 IFS="."
854 tmp=( $tmp )
855 IFS=$OLD_IFS
857 catalog_id_step_to TEST "${tmp[0]}"
859 test_item "${tmp[0]}" "${tmp[1]}" "${tmp[3]}"
860 ret=$?
862 [[ ! ( -n $2 && "$2" == "continue" ) ]] && exit
864 return $ret
867 args_clean ()
869 info "clean testing temp dir!\n"
874 args_exclude ()
876 exclude_id+=" $1"
900 # testcase目录下测试程序的调用,及输出比较。
904 # fsyntax: test_item <id> <script_name> <desc_str>
905 # fdesc: one item testing.
907 test_item ()
909 local ret=
910 local tmp=
911 local script_name=
912 local test_desc=
913 local exetime=
914 local tmp_vch_output=
916 script_name="$1.$2.sh"
917 test_desc="$3"
919 # paramter validation judgement.
920 if [[ ! -f $script_name ]]; then
921 err "err: file $script_name is not exist.\n"
922 return 1
925 if [[ -z "$test_desc" ]]; then
926 err "err: descript string is missing.\n"
927 return 1
930 if [[ ! -f $script_name."$test_desc".txt ]]; then
931 err "err: file $script_name.$test_desc.txt is not exist.\n"
932 return 1
935 # item testing string output.
936 # info "$CHIGHL$IFCCOLOR$TPREFIX[item] $1 $2 \"$3\" ... "
937 info "$CHIGHL$IFCCOLOR$TPREFIX[item] $1.\"$3\" ... "
940 # copy test item file to temp dir, it keeps every testing
941 # file can not be modified by test script.
943 rm "$TESTING_TMP_DIR/$1.$2/" -rf
944 mkdir -p "$TESTING_TMP_DIR/$1.$2/"{,scripts}
945 cp "$1".* "$TESTING_TMP_DIR/$1.$2/" -rf
946 cp -rf scripts/"$1".* "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null
947 # XXX: here should be modified, if the scripts dir is very large,
948 # it will copy every times for every test script.
949 cp -rf scripts/* "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null
950 cp -rf scripts/testing/ "$TESTING_TMP_DIR/$1.$2"/scripts/ 2> /dev/null
951 cd "$TESTING_TMP_DIR/$1.$2"
952 # dbgout_cmd ls -l
953 chmod +x *.sh scripts/* 2> /dev/null
955 # dispaly testing time cost if this item would cost more then 5 seconds.
956 if [[ -f $1.$2.time.txt ]]; then
957 exetime=`head -n 2 $1.$2.time.txt`
958 tmp=${exetime##$'\nreal '}
959 tmp=${tmp%%m*}
960 [[ -z $tmp ]] && err "err: the syntax of test time info is not correct.\n"
961 exetime=${exetime##*m}
962 exetime=${exetime%.*}
963 exetime=$(( tmp * 60 + exetime ))
964 # dispaly only longer then 5 seconds.
965 [[ -n $exetime && $exetime -gt 5 ]] && info "(time:${exetime}s) "
969 # here, re-direct output of test script, include stdout and stderr.
970 # using ttyout to force string output when debug this code, event if
971 # the stdout and stderr is re-directed.
973 # ttyout dbgout_ttydev=$dbgout_ttydev
975 # set output stream pipe.
976 tmp_vch_output=$vch_progstdout
977 [[ $output_disable_list =~ "info" ]] && tmp_vch_output=$vch_null
979 info "$CNORMAL"
980 # 带运行时间信息输出的测试项测试
981 if [[ $verbose == "enable" ]]; then
983 # time语句的code-block,stdout调试信息输出使用stderr,time语句输出到stderr,设置stderr输出为time.txt
984 # time语句内的code-block,stderr输出到stdout
985 # 这样,time的stderr输出到time.txt文件,time之内的code-block输出到vch_dbgout(stderr)
988 time ( {
989 info "\n${INFOCOLOR} + ###############################################${CNORMAL}\n" ;
990 { { ./$script_name; echo; } 2>&1 | tee log.txt; } | { IFS=$'\n'; while read -r line; do echo -ne "$verbos_pfx$line\n"; done } ;
991 info "${INFOCOLOR} + ###############################################${CNORMAL}\n" ;
992 } 2>&1 )
993 } >&$tmp_vch_output 2>time.txt
995 # ( time (
996 # info "abc\n";
997 # ttyout "testing\n";
998 # info "\n###############################################\n" ;
999 # ttyout "testing\n";
1000 # # 输出测试脚本的stdout和stderr到管道,管道的调试信息使用tee在控制台stdout输出,并保存到日志文件
1001 # ( ./$script_name 2>&1 ) | tee log.txt;
1002 # info "###############################################\n" ;
1003 # ttyout "testing\n";
1004 # ) 2>&1 # | { IFS=$'\n'; while read -r line; do echo "$verbos_pfx$line"; done } >&$vch_dbgout #2> /dev/null
1005 # ) 2> time.txt #2>&1
1006 else
1007 # an echo cmd append at the end of test script.
1008 # script output string though pipe, but there must be a '\n' at the end
1009 # of string, or it will not be displayed on screen.
1010 ( time ( ( ./$script_name; echo; ) > log.txt 2>&1 ) ) 2> time.txt #2>&1
1013 # append to log file.
1014 if [[ ! $logout_disable_list =~ "info" ]]; then
1015 # echo -ne "$INFO_PFX$@$NEWLINE_SFX" | tee -a $f_logout >&$vch_progstdout
1016 while read tmp; do
1017 echo "$tmp" >> $f_logout
1018 log_size_limit
1019 done < <(cat log.txt)
1022 # TBD:
1023 # cp log.txt $PWD/log/
1024 diff log.txt "$script_name.$test_desc".txt > diff.txt
1025 if [[ -z "`head -n 5 diff.txt`" ]]; then
1026 info "$CHIGHL$INFOCOLOR[ ok ]$CNORMAL\n"
1027 ret=0
1029 # 如果有failed record,进行记录。
1030 sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(catalog_id_get TEST)$/d" 2>/dev/null
1031 else
1032 info "$CHIGHL$EFCCOLOR[failed]$CNORMAL\n"
1033 if [[ $quiet != "enable" ]]; then
1034 info "testing result difference from correct output.\n"
1035 info "stdout > testout\n"
1036 info "###############################################\n"
1037 cat diff.txt |
1038 while read data; do
1039 case ${data:0:1} in
1040 '>' )
1041 info -ne "${FCL2R}>${CNORMAL}${data:1}\n"
1043 '<' )
1044 info -ne "${FCR2L}<${CNORMAL}${data:1}\n"
1047 info -ne "${data}\n"
1049 esac
1050 done
1051 # dbgout_cmd cat diff.txt # >&2
1052 # 将测试failed项的日志保存到log目录,便于测试后的查看。
1053 info "###############################################\n"
1055 ret=1
1057 # faled record
1058 sed -i $TESTING_TMP_DIR/testing_failed_list.txt -e "/^$(catalog_id_get TEST)$/d" 2>/dev/null
1059 catalog_id_get TEST >> $TESTING_TMP_DIR/testing_failed_list.txt
1062 cd - > /dev/null
1063 if [[ $update_test_file == "enable" ]]; then
1064 cp "$TESTING_TMP_DIR/$1.$2"/log.txt "$script_name.$test_desc".txt
1065 exetime=`head -n 2 $TESTING_TMP_DIR/$1.$2/time.txt`
1066 tmp=${exetime%%m*}
1067 tmp=${tmp##`echo -ne "\nreal "`} # }
1068 exetime=${exetime##*m}
1069 exetime=${exetime%.*}
1070 exetime=$(( tmp * 60 + exetime ))
1071 [[ -n $exetime && $exetime -gt 5 ]] && cp "$TESTING_TMP_DIR/$1.$2"/time.txt "$1.$2".time.txt
1074 # clean testing info
1075 rm "$TESTING_TMP_DIR/$1.$2/" -rf
1077 return $ret
1081 # test_unit <test_dir>
1082 test_unit ()
1084 local tmp=
1085 local test_dir=$1
1086 local ret=0
1087 local chkret=0
1088 local saved_test_id=
1090 cd "$1"
1091 test_cnt=`test_list_curr_content "$test_dirs" |
1092 ( while read line; do
1093 eval tmp=( $line )
1094 catalog_id_step_to TEST "${tmp[1]}"
1096 # id范围判断
1097 catalog_id_compare TEST "${tmp[1]}"
1098 chk_ret=$?
1099 # dbgoutd "chk_ret=$chk_ret\n"
1100 case $chk_ret in
1101 0 | 3 )
1105 continue
1108 break
1110 esac
1112 case ${tmp[0]} in
1113 "diritem" )
1115 cd "${tmp[4]}"
1117 TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4 + 4)) ' ')"
1118 #dbgoutd "TEST_DIR_DEPTH=$TEST_DIR_DEPTH\n"
1120 test_cnt=$(( test_cnt + 1 ))
1122 test_item "${tmp[1]}" "${tmp[3]}" "${tmp[2]}"
1124 if [[ $? != 0 ]]; then
1125 err_cnt=$(( err_cnt + 1 ))
1126 err_continue_cnt=$(( err_continue_cnt + 1 ))
1127 if [[ $test_ignor_err != "enable" ]]; then
1128 err "err interrupt ...\n"
1129 ret=1
1130 else
1131 ret=0
1132 [[ $err_continue_cnt -ge 10 ]] && ret=1
1134 else
1135 if [[ $err_continue_cnt != 0 ]]; then
1136 err_continue_cnt=0
1138 ret=0
1140 if [[ -n $test_cnt_num && $test_cnt -ge $test_cnt_num ]]; then
1141 ret=1
1144 # curr_test_id[$saved_test_id]="${tmp[1]}"
1145 # TEST_DIR_DEPTH=$(( TEST_DIR_DEPTH - 1 ))
1146 # TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ")
1148 cd ..
1150 [[ $ret == 1 ]] && break
1152 "item" )
1153 TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4 + 4)) ' ')"
1154 #dbgoutd "TEST_DIR_DEPTH=$TEST_DIR_DEPTH\n"
1156 test_cnt=$(( test_cnt + 1 ))
1158 test_item "${tmp[1]}" "${tmp[3]}" "${tmp[2]}"
1160 if [[ $? != 0 ]]; then
1161 err_cnt=$(( err_cnt + 1 ))
1162 err_continue_cnt=$(( err_continue_cnt + 1 ))
1163 if [[ $test_ignor_err != "enable" ]]; then
1164 err "err interrupt ...\n"
1165 ret=1
1166 else
1167 ret=0
1168 [[ $err_continue_cnt -ge 10 ]] && ret=1
1170 else
1171 if [[ $err_continue_cnt != 0 ]]; then
1172 err_continue_cnt=0
1174 ret=0
1176 if [[ -n $test_cnt_num && $test_cnt -ge $test_cnt_num ]]; then
1177 ret=1
1180 # curr_test_id[$saved_test_id]="${tmp[1]}"
1181 # TEST_DIR_DEPTH=$(( TEST_DIR_DEPTH - 1 ))
1182 # TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ")
1184 [[ $ret == 1 ]] && break
1186 "module" | "unit" | "dir" )
1187 if [[ -n $test_cnt_num && $test_cnt -gt $test_cnt_num ]]; then
1188 ret=1
1189 break
1192 catalog_id_step_into TEST "${tmp[1]}"
1194 TPREFIX="$(printf '%*s' $(( $TEST_DIR_DEPTH * 4)) ' ')"
1196 info "$CHIGHL$FCCOLOR$TPREFIX[${tmp[0]}] ${tmp[1]}.\"${tmp[2]}\" begin testing ...$CNORMAL\n"
1198 test_unit "${tmp[1]}.${tmp[3]}.${tmp[2]}.${tmp[0]}"
1199 ret=$?
1201 catalog_id_step_out TEST "${tmp[1]}"
1203 TPREFIX=$(printf "%*s" $(( $TEST_DIR_DEPTH * 4)) " ")
1204 [[ $ret != 0 ]] && break
1207 break
1209 esac
1210 [[ $chk_ret == 3 ]] && break
1211 done; echo $test_cnt $err_cnt $err_continue_cnt $TEST_CID_STATE $TEST_DIR_DEPTH ; return $ret ); return $?`
1213 # while语句由于|pipe操作符,以一个sub-process运行,所以使用return和exit都只是从sub-process中退出。
1214 # sub-proc中的环境变量test_cnt在return之前echo,在循环结束时echo,以stdout赋值给外部的test_cnt。
1215 ret=$?
1217 test_cnt=( $test_cnt )
1218 err_cnt=${test_cnt[1]}
1219 err_continue_cnt=${test_cnt[2]}
1220 catalog_id_set_init_state TEST "${test_cnt[3]}"
1222 TEST_DIR_DEPTH=${test_cnt[4]}
1223 unset test_cnt[1]
1224 unset test_cnt[2]
1226 [[ $err_continue_cnt -ge 10 ]] && info "连续10个测试项failed,暂停测试。\n" && ret=1
1228 cd ..
1229 return $ret
1232 readonly skip_file_pfx="="
1234 # 列出指定目录下的测试内容,包括模块、单元、目录、测试项
1235 # test_list_content <path>
1236 test_list_curr_content ()
1238 local tmp=
1239 local script_name=
1240 local test_desc=
1242 test_list_depth=$((test_list_depth++))
1244 if [[ -z $1 ]]; then
1245 tmp=
1246 else
1247 tmp="\"$1\""
1250 while read file; do
1251 # 忽略.txt文件,在处理.sh文件时再进行处理
1252 [[ $file =~ ".txt" ]] && continue
1254 # 以小数点分隔,包含3个字符串的为测试脚本
1255 # 包含3个字符串的为测试模块/单元/目录
1256 # 包含5个字符串的为测试项信息描述文件
1257 OLD_IFS=$IFS
1258 IFS="."
1259 tmp=( $file )
1260 IFS=$OLD_IFS
1262 # todo:添加非数字idx过滤
1263 # [[ ${tmp[1]} =~ "^[:digital:]" ]] && continue
1265 if [[ ${tmp[0]:0:1} == $skip_file_pfx ]]; then
1266 # ignor this file with "=" pfx.
1267 dbgoutd "'$file' is ignored.\n"
1268 elif [[ ${#tmp[@]} == 5 ]]; then
1269 test_desc=`ls -d -1 "$file.*.txt"`
1270 [[ -z "$test_desc" ]] && echo "err: 123aaa txt description file not found for $file." >&2 && return 1
1271 test_desc="${test_desc#$file\.}"
1272 test_desc="${test_desc%\.txt}"
1273 script_name=${tmp[1]}
1274 elif [[ ${#tmp[@]} == 4 ]]; then
1275 case ${tmp[3]} in
1276 "module" )
1277 echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\""
1279 "unit" )
1280 echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\""
1282 "dir" )
1283 echo "\"${tmp[3]}\" \"${tmp[0]}\" \"${tmp[2]}\" \"${tmp[1]}\""
1285 esac
1286 elif [[ ${#tmp[@]} == 3 ]]; then
1287 if [[ "${tmp[2]}" == "sh" ]]; then
1288 test_desc=`eval ls -d -1 "$file.*.txt"`
1290 [[ -z $test_desc ]] && echo "err: txt descript file not found for $file." >&2 && return 1
1291 test_desc=${test_desc#$file\.}
1292 test_desc=${test_desc%\.txt}
1294 echo "\"item\" \"${tmp[0]}\" \"$test_desc\" \"${tmp[1]}\""
1297 done < <(eval ls -1 "$tmp" | sort -n)
1299 test_list_depth=$((test_list_depth--))