diff --git a/.gitignore b/.gitignore index d963ae3d1f..0f6a29c17f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ test/data/sql/ .DS_Store vendor/ composer.lock - +test/runtime/* diff --git a/test/data/common/date/v1.yaml b/test/data/common/date/v1.yaml index 79bc7edd9f..776a992201 100644 --- a/test/data/common/date/v1.yaml +++ b/test/data/common/date/v1.yaml @@ -1,11 +1,11 @@ -title: moreDate +title: date desc: 系统可用日期类型 author: ly version: 1.0 -field: moreDate +field: date instances: - - instance: dateA + - instance: datetime fields: - field: year range: 2019-2022 @@ -30,7 +30,7 @@ instances: range: 0-59 format: "%02d" - - instance: dateB + - instance: date fields: - field: year range: 2019-2022 @@ -42,8 +42,3 @@ instances: - field: day range: 1-27 format: "%02d" - - - instance: dateC - fields: - - field: time - range: 1262275200-1893427200:R diff --git a/test/data/common/user/v1.yaml b/test/data/common/user/v1.yaml index 8c7b008430..32d69b9120 100644 --- a/test/data/common/user/v1.yaml +++ b/test/data/common/user/v1.yaml @@ -3,12 +3,13 @@ desc: 创建一些默认用户 author: ly version: 1.0 +field: user instances: - instance: user - note: 默认用户列表 fields: - - field: user + - field: account range: admin,dev1,dev2,dev3,test1,test2,test3 + - instance: userB note: 逗号拼接用户 fields: diff --git a/test/data/count.php b/test/data/count.php deleted file mode 100644 index 8c9967ced2..0000000000 --- a/test/data/count.php +++ /dev/null @@ -1,4 +0,0 @@ -dataRows = array(); -$config->dataRows['zt_action'] = 1000; -$config->dataRows['zt_activity'] = 1000; diff --git a/test/data/create.php b/test/data/create.php deleted file mode 100644 index a2b06da6d2..0000000000 --- a/test/data/create.php +++ /dev/null @@ -1,75 +0,0 @@ -setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置报错处理方式。 - $dbh->exec("SET GLOBAL sql_mode = '';"); - $dbh->exec("set names 'utf8'"); - $dbh->beginTransaction(); - - foreach($sqlFilePath as $file) - { - if(strpos($file, '.sql')) - { - $tableName = basename($file, '.sql'); - - $truncate = 'truncate table ' . $tableName; - $dbh->exec($truncate); - - $sql = file_get_contents($sqlDir . $file); - $count = $dbh->exec($sql); - echo $tableName . '表影响行数:' . $count . PHP_EOL; - } - } - - $dbh->commit(); - $dbh = null; // 关闭连接。 -} -catch (PDOException $e) -{ - die('Error!: ' . $e->getMessage() . PHP_EOL); -} diff --git a/test/data/demo/story/common/color/v1.yaml b/test/data/demo/story/common/color/v1.yaml deleted file mode 100644 index ea7b4f5b8a..0000000000 --- a/test/data/demo/story/common/color/v1.yaml +++ /dev/null @@ -1,13 +0,0 @@ -title: color -desc: 标题颜色 -author: ly -version: 1.0 - -field: color -instances: - - instance: color - note: 标题颜色 - fields: - - field: color - range: 3da7f5,75c941,2dbdb2,797ec9,ffaf38,ff4e3e - prefix: "#" diff --git a/test/data/demo/story/common/date/v1.yaml b/test/data/demo/story/common/date/v1.yaml deleted file mode 100644 index 79bc7edd9f..0000000000 --- a/test/data/demo/story/common/date/v1.yaml +++ /dev/null @@ -1,49 +0,0 @@ -title: moreDate -desc: 系统可用日期类型 -author: ly -version: 1.0 - -field: moreDate -instances: - - instance: dateA - fields: - - field: year - range: 2019-2022 - postfix: "-" - - field: month - range: 1-12 - format: "%02d" - postfix: "-" - - field: day - range: 1-27 - format: "%02d" - postfix: " " - - field: hour - range: 0-23 - format: "%02d" - postfix: ":" - - field: minute - range: 0-59 - format: "%02d" - postfix: ":" - - field: second - range: 0-59 - format: "%02d" - - - instance: dateB - fields: - - field: year - range: 2019-2022 - postfix: "-" - - field: month - range: 1-12 - format: "%02d" - postfix: "-" - - field: day - range: 1-27 - format: "%02d" - - - instance: dateC - fields: - - field: time - range: 1262275200-1893427200:R diff --git a/test/data/demo/story/common/user/v1.yaml b/test/data/demo/story/common/user/v1.yaml deleted file mode 100644 index e8a00c89fd..0000000000 --- a/test/data/demo/story/common/user/v1.yaml +++ /dev/null @@ -1,60 +0,0 @@ -title: user -desc: 创建一些默认用户 -author: ly -version: 1.0 - -instances: - - instance: user - note: 默认用户列表 - fields: - - field: user - range: admin,dev1,dev2,dev3,test1,test2,test3 - - instance: userB - note: 逗号拼接用户 - fields: - - field: user1 - range: admin - postfix: "," - - field: user2 - range: dev1 - postfix: "," - - field: user3 - range: dev2 - postfix: "," - - field: user4 - range: dev3 - postfix: "," - - field: user5 - range: test1 - postfix: "," - - field: user6 - range: test2 - postfix: "," - - field: user7 - range: test3 - - - instance: userC - note: 前后逗号拼接用户 - fields: - - field: user1 - range: admin - prefix: "," - postfix: "," - - field: user2 - range: dev1 - postfix: "," - - field: user3 - range: dev2 - postfix: "," - - field: user4 - range: dev3 - postfix: "," - - field: user5 - range: test1 - postfix: "," - - field: user6 - range: test2 - postfix: "," - - field: user7 - range: test3 - postfix: "," diff --git a/test/data/demo/story/config/config.yaml b/test/data/demo/story/config/config.yaml deleted file mode 100644 index 3fe3b10c20..0000000000 --- a/test/data/demo/story/config/config.yaml +++ /dev/null @@ -1,14 +0,0 @@ -说明: - 生成多个产品,为其添加计划、模块和需求。 - -数据: - 生成100个产品,每个产品生成5个计划和10个模块,每个计划关联20个软件需求,每个模块分配5个用户需求,5个软件需求。 - -调用yaml: - zd -c demo/story/zt_product.yaml -d zt_product.yaml -n 100 -o demo/story/sql/zt_product.sql -table zt_product - zd -c demo/story/zt_productplan.yaml -n 500 -d zt_productplan.yaml -o demo/story/sql/zt_productplan.sql -table zt_productplan - zd -c demo/story/zt_project.yaml -d zt_project.yaml -n 100 -o demo/story/sql/zt_project.sql -table zt_project - zd -c demo/story/zt_module.yaml -d zt_module.yaml -n 1000 -o demo/story/sql/zt_module.sql -table zt_module - zd -c demo/story/zt_story.yaml -d zt_story.yaml -n 10000 -o demo/story/sql/zt_story.sql -table zt_story - zd -c demo/story/zt_storyspec.yaml -n 10000 -d zt_storyspec.yaml -o demo/story/sql/zt_storyspec.sql -table zt_storyspec - zd -c demo/story/zt_action.yaml -n 11700 -o demo/story/sql/zt_action.sql -table zt_action diff --git a/test/data/demo/story/zt_action.yaml b/test/data/demo/story/zt_action.yaml deleted file mode 100644 index c373f289aa..0000000000 --- a/test/data/demo/story/zt_action.yaml +++ /dev/null @@ -1,66 +0,0 @@ -title: table zt_action -desc: "系统日志" -author: automated export -version: "1.0" -fields: - - field: objectType - note: "对象类型" - range: product{100},project{100},module{1000},story{10000},productplan{500} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: objectID - note: "对象ID" - range: 1-100,1-100,1-1000,1-10000,1-500 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: product - note: "产品" - range: 1-100 - prefix: "," - postfix: "," - loop: 0 - format: "" - - field: project - note: "项目" - range: 1-100 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: actor - note: "操作者" - range: "admin" - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: action - note: "动作" - range: opened - postfix: "" - loop: 0 - format: "" - - field: comment - note: "备注" - range: "1-10000" - prefix: "这是一个系统日志测试备注" - postfix: "" - loop: 0 - format: "" - - field: extra - note: "附加参数" - range: "0" - prefix: "" - postfix: "" - loop: 0 - - field: read - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_module.yaml b/test/data/demo/story/zt_module.yaml deleted file mode 100644 index 26f88ac79a..0000000000 --- a/test/data/demo/story/zt_module.yaml +++ /dev/null @@ -1,96 +0,0 @@ -title: table zt_module -desc: "模块" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: root - note: "根目录" - range: 1-100{10} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: branch - note: "分支" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: name - note: "模块名称" - range: 1-10000 - prefix: "需求模块" - postfix: "" - loop: 0 - format: "" - - field: parent - note: "父ID" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: path - note: "ID路径" - range: 1-10000 - prefix: "," - postfix: "," - loop: 0 - format: "" - - field: grade - note: "等级" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: order - note: "排序" - range: 10-100:10 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: type - note: "对象类型" - range: story - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: owner - note: "所有者" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: collector - note: "收藏者" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: short - note: "模块简称" - range: 1-10000 - prefix: "简称" - postfix: "" - loop: 0 - format: "" - - field: deleted - note: "是否删除" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_product.yaml b/test/data/demo/story/zt_product.yaml deleted file mode 100644 index e24912732f..0000000000 --- a/test/data/demo/story/zt_product.yaml +++ /dev/null @@ -1,143 +0,0 @@ -title: table zt_product -desc: "产品" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: program - note: "所属项目" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: name - note: "产品名称" - range: 1-10000 - prefix: "产品" - postfix: "" - loop: 0 - format: "" - - field: code - note: "产品代号" - range: 1-10000 - prefix: "code" - postfix: "" - loop: 0 - format: "" - - field: line - note: "产品线" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: type - note: "产品类型" - range: normal - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: status - note: "状态" - range: normal - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: subStatus - note: "子状态" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: desc - note: "产品描述" - range: 1-10000 - prefix: "这里是产品描述" - postfix: "" - loop: 0 - format: "" - - field: PO - note: "产品负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: QD - note: "测试负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: RD - note: "发布负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: acl - note: "访问控制" - range: open - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: whitelist - note: "分组白名单" - range: 1-10 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: createdBy - note: "创建者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: createdDate - note: "创建日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: createdVersion - note: "创建版本" - range: 20.0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: order - note: "排序" - range: 5-10000:5 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: deleted - note: "是否删除" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_productplan.yaml b/test/data/demo/story/zt_productplan.yaml deleted file mode 100644 index 6246f0a992..0000000000 --- a/test/data/demo/story/zt_productplan.yaml +++ /dev/null @@ -1,77 +0,0 @@ -title: table zt_productplan -desc: "产品计划" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: product - note: "产品" - range: 1-100{5} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: branch - note: "平台/分支" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parent - note: "父计划" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: title - note: "名称" - range: 1-10000 - prefix: "产品计划" - postfix: "" - loop: 0 - format: "" - - field: desc - note: "描述" - range: 1-10000 - prefix: "这里是描述" - postfix: "" - loop: 0 - format: "" - - field: begin - note: "开始日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: end - note: "结束日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: order - note: "排序" - range: 10-10000:5 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: deleted - note: "是否删除" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_project.yaml b/test/data/demo/story/zt_project.yaml deleted file mode 100644 index ea57cc0a8d..0000000000 --- a/test/data/demo/story/zt_project.yaml +++ /dev/null @@ -1,363 +0,0 @@ -title: table zt_project -desc: "项目" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: isCat - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: catID - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: template - note: "模块" - range: waterfall,scrum - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: category - note: "项目分类" - range: multiple - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: program - note: "所属项目" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: budget - note: "项目预算" - range: 1-100000:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: budgetUnit - note: "预算单位" - range: yuan - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: percent - note: "工作占比" - range: 1-100:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: privway - note: "私有的" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: milestone - note: "是否里程碑" - range: 0,1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: attribute - note: "阶段属性" - range: story,design,dev,qa,release,review,other - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: output - note: "输出文档" - range: 1-100:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: type - note: "项目类型" - range: sprint - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parent - note: "父级ID" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: path - note: "路径" - range: "0" - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: grade - note: "等级" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: name - note: "项目名称" - range: 1-10000 - prefix: "项目" - postfix: "" - loop: 0 - format: "" - - field: code - note: "项目代号" - range: 1-10000 - prefix: "project" - postfix: "" - loop: 0 - format: "" - - field: begin - note: "开始日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: end - note: "结束日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realStarted - note: "实际开始日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realFinished - note: "实际完成日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: days - note: "可用工作日" - range: 1-365:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: status - note: "状态" - range: doing,wait,suspended,closed - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: subStatus - note: "子状态" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: statge - note: "阶段" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: pri - note: "优先级" - range: 1-4 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: desc - note: "项目描述" - range: 1-10000 - prefix: "这是一个项目的描述" - postfix: "" - loop: 0 - format: "" - - field: version - note: "项目版本" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parentVersion - note: "父级项目版本" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realDuration - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: planDuration - note: "" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedBy - note: "创建者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedDate - note: "创建日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedVersion - note: "创建版本" - from: common.version.v1.yaml - use: version - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: closedBy - note: "关闭者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: closedDate - note: "关闭日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: canceledBy - note: "取消者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: canceledDate - note: "取消日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: PO - note: "产品负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: PM - note: "项目负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: QD - note: "测试负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: RD - note: "发布负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: team - note: "团队名称" - range: 1-10000 - prefix: "团队名称" - postfix: "" - loop: 0 - format: "" - - field: acl - note: "访问权限" - range: open - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: whitelist - note: "分组白名单" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: order - note: "项目排序" - range: 5-10000:5 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: deleted - note: "是否删除" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_story.yaml b/test/data/demo/story/zt_story.yaml deleted file mode 100644 index cc2d769a5f..0000000000 --- a/test/data/demo/story/zt_story.yaml +++ /dev/null @@ -1,135 +0,0 @@ -title: table zt_story -desc: "需求" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-100000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: program - note: "项目ID" - range: 1-100{100} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parent - note: "父需求ID" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: product - note: "所属产品" - range: 1-100{100} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: branch - note: "分支/平台" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: module - note: "所属模块" - range: 1-1000{10} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: plan - note: "所属计划" - range: 1-500{20} - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: source - note: "需求来源" - range: customer,user,po,market,service,operation,support,competitor,partner,dev,tester,bug,forum,other - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: sourceNote - note: "来源备注" - range: 1-100000 - prefix: "这里是需求来源备注" - postfix: "" - loop: 0 - format: "" - - field: fromBug - note: "来源Bug" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: title - note: "需求名称" - fields: - - field: field1 - range: 用户需求,软件需求 - - field: field2 - range: 1-100000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: keywords - note: "关键词" - range: 1-100000 - prefix: "关键词" - postfix: "" - loop: 0 - format: "" - - field: type - note: "需求类型" - range: requirement,story - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: pri - note: "优先级" - range: 1-4:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: estimate - note: "预计工时" - range: 0-20:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: status - note: "当前状态" - range: active - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: subStatus - note: "子状态" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: stage - note: "所处阶段" - range: wait - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/demo/story/zt_storyspec.yaml b/test/data/demo/story/zt_storyspec.yaml deleted file mode 100644 index 0cc93aca01..0000000000 --- a/test/data/demo/story/zt_storyspec.yaml +++ /dev/null @@ -1,44 +0,0 @@ -title: table zt_storyspec -desc: "需求描述" -author: automated export -version: "1.0" -fields: - - field: story - note: "需求ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: version - note: "版本" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: title - note: "标题" - fields: - - field: field1 - range: 用户需求,软件需求 - - field: field2 - range: 1-100000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: spec - note: "需求描述" - range: 1-10000 - prefix: "这是一个软件需求描述" - postfix: "" - loop: 0 - format: "" - - field: verify - note: "验收标准" - range: 1-10000 - prefix: "这是一个需求验收" - postfix: "" - loop: 0 - format: "" diff --git a/test/data/note.txt b/test/data/note.txt deleted file mode 100644 index 67219c0995..0000000000 --- a/test/data/note.txt +++ /dev/null @@ -1,133 +0,0 @@ -No set yet ZDATA: - zt_asset.yaml - zt_attendstat.yaml - zt_attend.yaml - zt_baseline.yaml - zt_basicmeas.yaml - zt_compile.yaml - zt_config.yaml - zt_deployproduct.yaml - zt_deployscope.yaml - zt_deploystep.yaml - zt_deploy.yaml - zt_derivemeas.yaml - zt_durationestimation.yaml - zt_faq.yaml - zt_feedbackview.yaml - zt_feedback.yaml - zt_flow_reviewlist.yaml - zt_flow_workloadbudget.yaml - zt_host.yaml - zt_leave.yaml - zt_lieu.yaml - zt_measqueue.yaml - zt_measrecords.yaml - zt_meastemplate.yaml - zt_nc.yaml - zt_oauth.yaml - zt_overtime.yaml - zt_programplan.yaml - zt_programprocess.yaml - zt_programreport.yaml - zt_relationoftasks.yaml - zt_service.yaml - zt_sqlview.yaml - zt_storystage.yaml - zt_suitecase.yaml - zt_trip.yaml - zt_webhook.yaml - zt_weeklyreport.yaml - zt_workestimation.yaml - zt_workflowaction.yaml - zt_workflowdatasource.yaml - zt_workflowfield.yaml - zt_workflowlabel.yaml - zt_workflowlayout.yaml - zt_workflowlinkdata.yaml - zt_workflowrelationlayout.yaml - zt_workflowrelation.yaml - zt_workflowrule.yaml - zt_workflowsql.yaml - zt_workflowversion.yaml - zt_workflow.yaml - -==================================================== -set ZDATA: - zt_action.yaml - zt_branch.yaml - zt_block.yaml - zt_budget.yaml - zt_bug.yaml - zt_build.yaml - zt_burn.yaml - zt_casestep.yaml - zt_case.yaml - zt_company.yaml - zt_cron.yaml - zt_dept.yaml - zt_doccontent.yaml - zt_doclib.yaml - zt_doc.yaml - zt_effort.yaml - zt_entry.yaml - zt_extension.yaml - zt_file.yaml - zt_flow_audit.yaml - zt_flow_auditcl.yaml - zt_flow_auditplan.yaml - zt_flow_auditresult.yaml - zt_flow_cmcl.yaml - zt_flow_design.yaml - zt_flow_designspec.yaml - zt_flow_issue.yaml - zt_flow_output.yaml - zt_flow_process.yaml - zt_flow_reviewcl.yaml - zt_flow_risk.yaml - zt_flow_stage.yaml - zt_grouppriv.yaml - zt_group.yaml - zt_history.yaml - zt_jenkins.yaml - zt_job.yaml - zt_lang.yaml - zt_log.yaml - zt_module.yaml - zt_notify.yaml - zt_object.yaml - zt_productplan.yaml - zt_project.yaml - zt_programactivity.yaml - zt_programoutput.yaml - zt_project.yaml - zt_projectproduct.yaml - zt_projectspec.yaml - zt_projectstory.yaml - zt_relation.yaml - zt_release.yaml - zt_repo.yaml - zt_repobranch.yaml - zt_repofiles.yaml - zt_repohistory.yaml - zt_report.yaml - zt_review.yaml - zt_reviewissue.yaml - zt_reviewresult.yaml - zt_score.yaml - zt_searchindex.yaml - zt_serverroom.yaml - zt_solutions.yaml - zt_storyspec.yaml - zt_story.yaml - zt_taskspec.yaml - zt_task.yaml - zt_team.yaml - zt_testreport.yaml - zt_testresult.yaml - zt_testrun.yaml - zt_testsuite.yaml - zt_todo.yaml - zt_usercontact.yaml - zt_userquery.yaml - zt_userview.yaml - zt_user.yaml diff --git a/test/data/project.yaml b/test/data/project.yaml new file mode 100644 index 0000000000..91e7e4be8a --- /dev/null +++ b/test/data/project.yaml @@ -0,0 +1,69 @@ +title: table zt_project +author: Zhu Jinyong +version: "1.0" +fields: + - field: id + range: 1-10000 + - field: project + range: 1-10000 + - field: model + range: + - field: type + range: project + - field: product + range: single + - field: lifetime + range: + - field: budget + range: 0 + - field: budgetUnit + range: CNY,USD + - field: attribute + note: "Only stage has attribute" + range: + - field: percent + range: 1-100:R + - field: milestone + note: "Is it milestone" + range: 0 + - field: output + note: "Output document" + range: + - field: auth + note: "Only project has auth" + range: + - field: parent + range: 1,2,3,4,2,1,[1-7]{2},[7-19]{3} + - field: path + prefix: "," + postfix: "," + range: + - field: grade + range: + - field: name + range: 1-10000 + prefix: "测试项目" + - field: code + range: 1-10000 + prefix: "project" + - field: begin + from: common.date.v1.yaml + use: date + - field: PO + range: + - field: PM + range: + - field: QD + range: + - field: RD + range: + - field: team + range: + - field: acl + range: open,private,custom + - field: whitelist + range: + - field: order + range: 5-10000:5 + - field: deleted + range: 0 diff --git a/test/data/zentao/config.php b/test/data/zentao/config.php new file mode 100644 index 0000000000..21b8c3ca3c --- /dev/null +++ b/test/data/zentao/config.php @@ -0,0 +1,6 @@ +programGrade1 = array('rows' => 10, 'data' => array('project', 'program', 'programgrade1')); +//$builder->programGrade2 = array('rows' => 10, 'data' => array('project', 'program', 'programgrade2')); +//$builder->programGrade3 = array('rows' => 10, 'data' => array('project', 'program', 'programgrade3')); + diff --git a/test/data/zentao/program.yaml b/test/data/zentao/program.yaml new file mode 100644 index 0000000000..91ae0a8346 --- /dev/null +++ b/test/data/zentao/program.yaml @@ -0,0 +1,22 @@ +title: program +author: Zhu Jinyong +version: "1.0" +fields: + - field: id + range: 1-10000 + - field: project + range: 1-10000 + - field: model + range: + - field: type + range: program + - field: status + range: doing,wait,suspended,closed + - field: desc + range: 1-10000 + prefix: "项目集描述" + - field: acl + range: open,private + - field: whitelist + from: common.user.v1.yaml + use: user diff --git a/test/data/zentao/programgrade1.yaml b/test/data/zentao/programgrade1.yaml new file mode 100644 index 0000000000..f24cc4495e --- /dev/null +++ b/test/data/zentao/programgrade1.yaml @@ -0,0 +1,10 @@ +title: program +author: Zhu Jinyong +version: "1.0" +fields: + - field: grade + range: 1 + - field: parent + range: 1 + - field: path + range: 1 diff --git a/test/data/zentao/programgrade2.yaml b/test/data/zentao/programgrade2.yaml new file mode 100644 index 0000000000..f24cc4495e --- /dev/null +++ b/test/data/zentao/programgrade2.yaml @@ -0,0 +1,10 @@ +title: program +author: Zhu Jinyong +version: "1.0" +fields: + - field: grade + range: 1 + - field: parent + range: 1 + - field: path + range: 1 diff --git a/test/data/zentao/programgrade3.yaml b/test/data/zentao/programgrade3.yaml new file mode 100644 index 0000000000..f24cc4495e --- /dev/null +++ b/test/data/zentao/programgrade3.yaml @@ -0,0 +1,10 @@ +title: program +author: Zhu Jinyong +version: "1.0" +fields: + - field: grade + range: 1 + - field: parent + range: 1 + - field: path + range: 1 diff --git a/test/data/zentao/project.yaml b/test/data/zentao/project.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/data/zt_project.yaml b/test/data/zt_project.yaml deleted file mode 100644 index a6509b5db9..0000000000 --- a/test/data/zt_project.yaml +++ /dev/null @@ -1,363 +0,0 @@ -title: table zt_project -desc: "项目" -author: automated export -version: "1.0" -fields: - - field: id - note: "ID" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: isCat - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: catID - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: template - note: "模块" - range: waterfall,scrum - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: category - note: "项目分类" - range: multiple,single - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: program - note: "所属项目" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: budget - note: "项目预算" - range: 1-100000:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: budgetUnit - note: "预算单位" - range: yuan,Dollars - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: percent - note: "工作占比" - range: 1-100:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: privway - note: "私有的" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: milestone - note: "是否里程碑" - range: 0,1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: attribute - note: "阶段属性" - range: story,design,dev,qa,release,review,other - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: output - note: "输出文档" - range: 1-100:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: type - note: "项目类型" - range: waterfall,project - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parent - note: "父级ID" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: path - note: "路径" - range: "0" - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: grade - note: "等级" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: name - note: "项目名称" - range: 1-10000 - prefix: "这是一个项目名称" - postfix: "" - loop: 0 - format: "" - - field: code - note: "项目代号" - range: 1-10000 - prefix: "project" - postfix: "" - loop: 0 - format: "" - - field: begin - note: "开始日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: end - note: "结束日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realStarted - note: "实际开始日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realFinished - note: "实际完成日期" - from: common.date.v1.yaml - use: dateB - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: days - note: "可用工作日" - range: 1-365:R - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: status - note: "状态" - range: doing,wait,suspended,closed - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: subStatus - note: "子状态" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: statge - note: "阶段" - range: 1 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: pri - note: "优先级" - range: 1-4 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: desc - note: "项目描述" - range: 1-10000 - prefix: "这是一个项目的描述" - postfix: "" - loop: 0 - format: "" - - field: version - note: "项目版本" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: parentVersion - note: "父级项目版本" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: realDuration - note: "" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: planDuration - note: "" - range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedBy - note: "创建者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedDate - note: "创建日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: openedVersion - note: "创建版本" - from: common.version.v1.yaml - use: version - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: closedBy - note: "关闭者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: closedDate - note: "关闭日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: canceledBy - note: "取消者" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: canceledDate - note: "取消日期" - from: common.date.v1.yaml - use: dateA - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: PO - note: "产品负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: PM - note: "项目负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: QD - note: "测试负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: RD - note: "发布负责人" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: team - note: "团队名称" - range: 1-10000 - prefix: "团队名称" - postfix: "" - loop: 0 - format: "" - - field: acl - note: "访问权限" - range: open,private,custom - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: whitelist - note: "分组白名单" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: order - note: "项目排序" - range: 5-10000:5 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: deleted - note: "是否删除" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/lib/spyc.php b/test/lib/spyc.php new file mode 100644 index 0000000000..3fe0f62d9a --- /dev/null +++ b/test/lib/spyc.php @@ -0,0 +1,1186 @@ + + * @author Chris Wanstrath + * @link https://github.com/mustangostang/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +if (!function_exists('spyc_dump')) { + /** + * Dumps array to YAML. + * @param array $data Array. + * @return string + */ + function spyc_dump ($data) { + return Spyc::YAMLDump($data, false, false, true); + } +} + +if (!class_exists('Spyc')) { + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_empty_hash_as_object = false; + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->_loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->_load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + * @param array set options + */ + public static function YAMLLoad($input, $options = []) { + $Spyc = new Spyc; + foreach ($options as $key => $value) { + if (property_exists($Spyc, $key)) { + $Spyc->$key = $value; + } + } + return $Spyc->_load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + * @param array set options + */ + public static function YAMLLoadString($input, $options = []) { + $Spyc = new Spyc; + foreach ($options as $key => $value) { + if (property_exists($Spyc, $key)) { + $Spyc->$key = $value; + } + } + return $Spyc->_loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array|\stdClass $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + * @param bool $no_opening_dashes Do not start YAML file with "---\n" + */ + public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { + $spyc = new Spyc; + return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = ""; + if (!$no_opening_dashes) $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if(is_object($value)) $value = (array)$value; + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if ($value === "") $value = '""'; + if (self::isTranslationWord($value)) { + $value = $this->_doLiteralBlock($value, $indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = $value ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) { + $newValue = $exploded[0]; + unset($exploded[0]); + } + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $line = trim($line); + if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) { + $line = substr($line, 1, -1); + } + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + if (is_numeric($value) && is_string($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + + private function isTrueWord($value) { + $words = self::getTranslations(array('true', 'on', 'yes', 'y')); + return in_array($value, $words, true); + } + + private function isFalseWord($value) { + $words = self::getTranslations(array('false', 'off', 'no', 'n')); + return in_array($value, $words, true); + } + + private function isNullWord($value) { + $words = self::getTranslations(array('null', '~')); + return in_array($value, $words, true); + } + + private function isTranslationWord($value) { + return ( + self::isTrueWord($value) || + self::isFalseWord($value) || + self::isNullWord($value) + ); + } + + /** + * Coerce a string into a native type + * Reference: http://yaml.org/type/bool.html + * TODO: Use only words from the YAML spec. + * @access private + * @param $value The value to coerce + */ + private function coerceValue(&$value) { + if (self::isTrueWord($value)) { + $value = true; + } else if (self::isFalseWord($value)) { + $value = false; + } else if (self::isNullWord($value)) { + $value = null; + } + } + + /** + * Given a set of words, perform the appropriate translations on them to + * match the YAML 1.1 specification for type coercing. + * @param $words The words to translate + * @access private + */ + private static function getTranslations(array $words) { + $result = array(); + foreach ($words as $i) { + $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); + } + return $result; + } + +// LOADING FUNCTIONS + + private function _load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function _loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ("\n", $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= ' '.$this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + // Strip out comments + if (strpos ($line, '#')) { + $line = preg_replace('/\s*#([^"\']+)$/','',$line); + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + $input = file_get_contents($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) { + return $this->returnMappedSequence($line); + } + + if ($this->startsMappedValue($line)) { + return $this->returnMappedValue($line); + } + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return ""; + + if ($this->setting_empty_hash_as_object && $value === '{}') { + return new stdClass(); + } + + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) { + $value = str_replace('\n', "\n", $value); + if ($first_character == "'") + return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\'')); + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\'')); + } + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { + // Hexadecimal value. + return hexdec($value); + } + + $this->coerceValue($value); + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + $saved_empties = array(); + + // Check for empty strings + $regex = '/("")|(\'\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_empties = $strings[0]; + $inline = preg_replace($regex,'YAMLEmpty',$inline); + } + unset($regex); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + // echo $inline; + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(',',$inline); + $explode = array_map('trim', $explode); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + + // Re-add the empties + if (!empty($saved_empties)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLEmpty') !== false) { + $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLEmpty') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line || !is_scalar($line)) return false; + if (substr($line, 0, 2) != '- ') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function checkKeysInValue($value) { + if (strchr('[{"\'', $value[0]) === false) { + if (strchr($value, ': ') !== false) { + throw new Exception('Too many keys: '.$value); + } + } + } + + private function returnMappedValue ($line) { + $this->checkKeysInValue($line); + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ': ')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(': ', $line); + $key = trim(array_shift($explode)); + $value = trim(implode(': ', $explode)); + $this->checkKeysInValue($value); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + if ($this->isArrayElement($value)) { + $value = $this->returnArrayElement($value); + } + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} +} + +// Enable use of Spyc from command line +// The syntax is the following: php Spyc.php spyc.yaml + +do { + if (PHP_SAPI != 'cli') break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break; + $file = $argv[1]; + echo json_encode (spyc_load_file ($file)); +} while (0); diff --git a/test/lib/utils.php b/test/lib/utils.php index 26ede00b47..eb9d17bfcc 100644 --- a/test/lib/utils.php +++ b/test/lib/utils.php @@ -10,6 +10,27 @@ * @link http://www.zentao.net */ +define('RUNTIME_ROOT', dirname(dirname(__FILE__)) . '/runtime/'); +define('LIB_ROOT', dirname(dirname(__FILE__)) . '/lib/'); + +/** + * Get version type of ZenTaoPMS. + * + * @param $version + * @access public + * @return void + */ +function getVersionType($version) +{ + global $config; + + if(strpos($version, 'max') !== false) return 'max'; + if(strpos($version, 'biz') !== false) return 'biz'; + if(strpos($version, 'pro') !== false) return 'pro'; + + return 'zentao'; +} + /** * Run test cases of a directory using ztf. * @@ -21,70 +42,127 @@ function ztfRun($dir) { global $config; - $ztfPath = dirname(dirname(__FILE__)) . '/tools/ztf'; + $ztfPath = RUNTIME_ROOT . 'ztf'; $command = "$ztfPath $dir"; system($command); } /** - * Run scripts of a directory using zendata. + * Extract comments to steps and expects. * * @param string $dir * @access public * @return void */ -function zdRun($dir) +function ztfExtract($dir) +{ + global $config; + + $ztfPath = RUNTIME_ROOT . 'ztf'; + $command = "$ztfPath extract $dir"; + system($command); +} + +/** + * Run yaml files of zendata. + * + * @access public + * @return void + */ +function zdRun() { $frameworkRoot = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR; include $frameworkRoot . 'helper.class.php'; + include LIB_ROOT . 'spyc.php'; - $zdRoot = dirname(dirname(__FILE__)) . '/' . $dir; - $zdPath = dirname(dirname(__FILE__)) . '/tools/zd'; + $zdRoot = dirname(dirname(__FILE__)) . '/data/'; + $zdPath = RUNTIME_ROOT . 'zd'; set_time_limit(0); try { $config = new stdclass(); $config->db = new stdclass(); - include dirname(dirname(dirname(__FILE__))) . '/config/config.php'; - include $zdRoot . '/count.php'; + include dirname(dirname(dirname(__FILE__))) . '/config/config.php'; + + $versionType = getVersionType($config->version); + $configRoot = $zdRoot . $versionType . '/'; + include $configRoot . 'config.php'; + + /* Connect to MySQL. */ $dsn = "mysql:host={$config->db->host}:{$config->db->port};dbname={$config->db->name}"; $dbh = new PDO($dsn, $config->db->user, $config->db->password); echo 'MySQL connect success' . PHP_EOL; - $command = "$zdPath -c $zdRoot/%s -n %s -o $zdRoot/sql/%s.sql -table %s"; - $yamlFilePath = scandir($zdRoot); - foreach($yamlFilePath as $file) - { - if(!strpos($file, '.yaml')) continue; - - $fileName = basename($file, '.yaml'); - $count = isset($config->dataRows[$fileName]) ? $config->dataRows[$fileName] : 10; - $execYaml = sprintf($command, $file, $count, $fileName, $fileName); - exec($execYaml); // Create sql files. - - echo 'Execute: ' . $file . PHP_EOL; - } - - /* Export SQL files to mysql. */ - $sqlDir = $zdRoot . '/sql/'; - $sqlFilePath = scandir($sqlDir); - $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置报错处理方式。 $dbh->exec("SET GLOBAL sql_mode = '';"); $dbh->exec("set names 'utf8'"); $dbh->beginTransaction(); - + + $command = "$zdPath -c %s -d $zdRoot%s -n %s -o {$zdRoot}sql/%s.sql -table %s"; + $tables = array(); + foreach($builder as $key => $info) + { + /* Build zendata. */ + $configData = array('fields' => array()); + foreach($info['data'] as $fileKey => $fileName) + { + if($fileKey == 0) continue; // Skip default file. + + $data = Spyc::YAMLLoad($configRoot . $fileName . '.yaml'); + foreach($data['fields'] as $field) + { + $fieldName = $field['field']; + $fieldExist = false; + foreach($configData['fields'] as $key => $configField) + { + if($configField['field'] == $fieldName) + { + $configData['fields'][$key] = $field; + $fieldExist = true; + break; + } + } + + if(!$fieldExist) $configData['fields'][] = $field; + } + } + + /* Refresh runtime/tmp/config.yaml. */ + $spyc = new Spyc(); + $content = $spyc->dump($configData); + $yaml = fopen(RUNTIME_ROOT . 'tmp/config.yaml', 'w'); + fwrite($yaml, $content); + fclose($yaml); + + /* Create sql files. */ + $defaultName = $info['data'][0]; + $tableName = $config->db->prefix . $defaultName; + + $execYaml = sprintf($command, RUNTIME_ROOT . 'tmp/config.yaml', $defaultName . '.yaml', $info['rows'], $fileName, $tableName); + system($execYaml); + echo 'Execute: ' . $fileName . PHP_EOL; + + $tables[$tableName] = $tableName; + } + + /* Truncate tables. */ + foreach($tables as $table) + { + $dbh->exec('truncate table ' . $table); + } + + /* Export SQL files to MySQL. */ + $sqlDir = $zdRoot . '/sql/'; + $sqlFilePath = scandir($sqlDir); + foreach($sqlFilePath as $file) { if(!strpos($file, '.sql')) continue; $tableName = basename($file, '.sql'); - $truncate = 'truncate table ' . $tableName; - $dbh->exec($truncate); - $sql = file_get_contents($sqlDir . $file); $count = $dbh->exec($sql); echo $tableName . ' insert rows ' . $count . PHP_EOL; diff --git a/test/model/branch/getbyid.php b/test/model/branch/getbyid.php deleted file mode 100755 index 928829dbbb..0000000000 --- a/test/model/branch/getbyid.php +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env php -loadModel('branch'); - -/* group: 1. */ -r($branch->getByID(1)) && p('name') && e('A'); // step: 1.1 使用branchID获取一个存在的分支. >> diff --git a/test/model/gapanalysis/getbyid.php b/test/model/gapanalysis/getbyid.php deleted file mode 100755 index bd18dec82f..0000000000 --- a/test/model/gapanalysis/getbyid.php +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env php -> `\d,\d+,\w+\d` - 2. 使用ID获取一个不存在的能力差距分析 >> `` -[esac] -*/ -$gapanalysis = $tester->loadModel('gapanalysis'); - -$app->dbh->query("truncate zt_gapanalysis"); -$id = rand(1,5); -zdImport(TABLE_GAPANALYSIS, "zendata/gapanalysis.yaml", 5); - -$randGapAnalysis = $tester->dao->select('*,rand() as rand')->from(TABLE_GAPANALYSIS)->where('id')->eq($id)->orderBy('rand')->fetch(); -if(!$randGapAnalysis) exit("Prepair data error."); -unset($randGapAnalysis->rand); - -/* Step 1.*/ -run($gapanalysis->getByID($randGapAnalysis->id, 'id')) and expect('id,project,account'); - -/* Step 2.*/ -run($gapanalysis->getByID(null, 'id')) and expect('id'); diff --git a/test/model/trainplan/getbyid.php b/test/model/trainplan/getbyid.php deleted file mode 100755 index 0f20b2399b..0000000000 --- a/test/model/trainplan/getbyid.php +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env php -> `21,hufangzhou` -*/ -include dirname(dirname(dirname(__FILE__))) . '/init.php'; - -$trainplan = $tester->loadModel('trainplan'); - -$app->dbh->query("truncate zt_trainplan"); -zdImport(TABLE_TRAINPLAN, "zendata/trainplan.yaml", 10); - -$randTrainPlan = $tester->dao->select('*,rand() as rand')->from(TABLE_TRAINPLAN)->orderBy('rand')->fetch(); -if(!$randTrainPlan) exit("Prepair data error."); -unset($randTrainPlan->rand); - -/* Step 1.*/ -run($trainplan->getById($randTrainPlan->id)) and expect('project,lecturer'); diff --git a/test/model/user/getbyid.php b/test/model/user/getbyid.php index b1643434ab..7e186d9acf 100755 --- a/test/model/user/getbyid.php +++ b/test/model/user/getbyid.php @@ -1,16 +1,15 @@ #!/usr/bin/env php > `\d,\w+` - 2. 使用account获取一个存在的用户 >> `\d` - 3. 使用account获取一个存在的用户 >> `` -[esac] + + + */ $user = $tester->loadModel('user'); @@ -28,4 +27,4 @@ run($user->getByID($randUser->id, 'id')) and expect('id,account'); run($user->getByID($randUser->account, 'account')) and expect('id'); /* Step 3.*/ -run($user->getByID(null, 'id')) and expect('id'); +run($user->getByID(null, 'id')) and expect('id'); \ No newline at end of file diff --git a/test/ztest b/test/ztest index 76b3ccf8d4..eb0990ada1 100755 --- a/test/ztest +++ b/test/ztest @@ -9,10 +9,20 @@ switch($argv[1]) case 'init': zdRun('data'); break; + case 'extract': + ztfExtract('model'); + break; + case 'api': + ztfExtract('api'); + ztfRun('api'); + break; case 'control': ztfRun('control'); break; case 'model': ztfRun('model'); break; + default: + ztfExtract($argv[1]); + system("php " . $argv[1]); }