diff --git a/module/block/test/zen/printproductdocblock.php b/module/block/test/zen/printproductdocblock.php index 115e1b2bdd..e002666b63 100755 --- a/module/block/test/zen/printproductdocblock.php +++ b/module/block/test/zen/printproductdocblock.php @@ -11,6 +11,12 @@ cid=0 - 执行$result1->type @involved - 执行$result2->success @1 - 执行$result3->type @all +- 执行$result4->success @1 +- 执行$result4->type @involved +- 执行$result5->productsCount @10 +- 执行$result5->totalDocsCount @10 +- 执行$result6->success @1 +- 执行$result7->success @1 */ @@ -25,12 +31,33 @@ su('admin'); $blockTest = new blockTest(); +// 测试步骤1:测试默认参数下获取产品文档区块数据 $result1 = $blockTest->printProductDocBlockTest(); r($result1->success) && p() && e('1'); r($result1->type) && p() && e('involved'); +// 测试步骤2:测试指定count参数限制文档数量 $result2 = $blockTest->printProductDocBlockTest((object)array('params' => (object)array('count' => 5))); r($result2->success) && p() && e('1'); +// 测试步骤3:测试type参数为all时获取所有产品文档 $result3 = $blockTest->printProductDocBlockTest(null, array('type' => 'all')); -r($result3->type) && p() && e('all'); \ No newline at end of file +r($result3->type) && p() && e('all'); + +// 测试步骤4:测试空block参数和空params参数的处理 +$result4 = $blockTest->printProductDocBlockTest(null, array()); +r($result4->success) && p() && e('1'); +r($result4->type) && p() && e('involved'); + +// 测试步骤5:测试产品文档分组和数量统计功能 +$result5 = $blockTest->printProductDocBlockTest(); +r($result5->productsCount) && p() && e('10'); +r($result5->totalDocsCount) && p() && e('10'); + +// 测试步骤6:测试边界值count为0的情况 +$result6 = $blockTest->printProductDocBlockTest((object)array('params' => (object)array('count' => 0))); +r($result6->success) && p() && e('1'); + +// 测试步骤7:测试极大count值的处理 +$result7 = $blockTest->printProductDocBlockTest((object)array('params' => (object)array('count' => 999))); +r($result7->success) && p() && e('1'); \ No newline at end of file diff --git a/module/convert/test/tao/importjirachangeitem.php b/module/convert/test/tao/importjirachangeitem.php index 0a43696c72..4fac3a2630 100755 --- a/module/convert/test/tao/importjirachangeitem.php +++ b/module/convert/test/tao/importjirachangeitem.php @@ -7,7 +7,7 @@ title=测试 convertTao::importJiraChangeItem(); timeout=0 cid=0 -- 测试步骤1:导入空数组数据 @true +- 步骤1:导入空数组数据 @true */ @@ -20,11 +20,11 @@ global $tester; $sql = <<importJiraChangeItemTest(array())) && p() && e('true'); // 测试步骤1:导入空数组数据 +r($convertTest->importJiraChangeItemTest(array())) && p() && e('true'); // 步骤1:导入空数组数据 r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 10, + 'id' => 100, 'groupid' => 1, 'field' => 'status', 'oldstring' => 'Open', 'newstring' => 'In Progress' ) -))) && p() && e('true'); // 测试步骤2:导入有效的ChangeItem数据 +))) && p() && e('true'); // 步骤2:导入有效的ChangeItem数据 r($convertTest->importJiraChangeItemTest(array( (object)array( @@ -86,75 +86,85 @@ r($convertTest->importJiraChangeItemTest(array( 'oldstring' => 'Open', 'newstring' => 'Closed' ) -))) && p() && e('true'); // 测试步骤3:导入已存在关联关系的数据 +))) && p() && e('true'); // 步骤3:导入已存在关联关系的数据 r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 11, + 'id' => 101, 'groupid' => 999, 'field' => 'status', 'oldstring' => 'Open', 'newstring' => 'Closed' ) -))) && p() && e('true'); // 测试步骤4:导入无效ChangeGroup数据 +))) && p() && e('true'); // 步骤4:导入无效ChangeGroup数据 r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 21, + 'id' => 102, 'groupid' => 3, 'field' => 'status', 'oldstring' => 'Open', 'newstring' => 'Closed' ) -))) && p() && e('true'); // 测试步骤5:导入不存在Issue的数据 +))) && p() && e('true'); // 步骤5:导入不存在Issue的数据 r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 16, + 'id' => 103, 'groupid' => 1, 'field' => 'description', - 'oldstring' => 'Bug with ', - 'newstring' => 'Fixed: Bug with "quotes" and \'apostrophes\' & special chars' + 'oldstring' => 'Bug with ', + 'newstring' => 'Fixed: Bug with "quotes" and \'apostrophes\' & special chars < >' ) -))) && p() && e('true'); // 测试步骤6:导入包含特殊字符的数据 +))) && p() && e('true'); // 步骤6:导入包含HTML和特殊字符的数据 r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 18, + 'id' => 104, 'groupid' => 1, 'field' => 'components', 'oldstring' => null, - 'newstring' => 'UI,Backend' + 'newstring' => 'UI,Backend,Database' ), (object)array( - 'id' => 19, + 'id' => 105, 'groupid' => 2, 'field' => 'fixVersion', 'oldstring' => '1.0.0', 'newstring' => null ) -))) && p() && e('true'); // 测试步骤7:导入边界值数据(null值) +))) && p() && e('true'); // 步骤7:导入边界值数据(null值处理) r($convertTest->importJiraChangeItemTest(array( (object)array( - 'id' => 12, + 'id' => 106, 'groupid' => 1, 'field' => 'priority', 'oldstring' => 'High', 'newstring' => 'Critical' ), (object)array( - 'id' => 13, + 'id' => 107, 'groupid' => 2, 'field' => 'resolution', 'oldstring' => '', 'newstring' => 'Fixed' ), (object)array( - 'id' => 14, + 'id' => 108, 'groupid' => 1, 'field' => 'assignee', - 'oldstring' => 'user1', - 'newstring' => 'user2' + 'oldstring' => 'user1@company.com', + 'newstring' => 'user2@company.com' ) -))) && p() && e('true'); // 测试步骤8:导入批量混合状态数据 \ No newline at end of file +))) && p() && e('true'); // 步骤8:导入批量混合状态数据(包含邮箱格式) + +r($convertTest->importJiraChangeItemTest(array( + (object)array( + 'id' => 109, + 'groupid' => 1, + 'field' => 'summary', + 'oldstring' => '这是一个中文标题', + 'newstring' => 'This is an English title' + ) +))) && p() && e('true'); // 步骤9:导入多语言数据测试 \ No newline at end of file diff --git a/module/convert/test/tao/importjiraproject.php b/module/convert/test/tao/importjiraproject.php index b3e2a418fc..9e2695fdac 100755 --- a/module/convert/test/tao/importjiraproject.php +++ b/module/convert/test/tao/importjiraproject.php @@ -42,24 +42,47 @@ if(!defined('JIRA_TMPRELATION')) define('JIRA_TMPRELATION', '`jiratmprelation`') try { $tester->dbh->exec('DELETE FROM zt_project WHERE name LIKE "Test%" OR name LIKE "测试%"'); $tester->dbh->exec('DELETE FROM zt_product WHERE name LIKE "Test%" OR name LIKE "测试%"'); + // $tester->dbh->exec('DELETE FROM zt_execution WHERE name LIKE "Test%" OR name LIKE "测试%"'); // execution表可能不存在 $tester->dbh->exec('TRUNCATE TABLE jiratmprelation'); } catch (Exception $e) { // 忽略清理错误 } -// 使用最简单的zendata准备 +// 准备更完整的测试数据 $user = zenData('user'); -$user->gen(10); +$user->account->range('admin,user1,user2,user3,testuser1,testuser2,testuser3,testuser4,testuser5'); +$user->realname->range('管理员,用户1,用户2,用户3,测试用户1,测试用户2,测试用户3,测试用户4,测试用户5'); +$user->password->range('123456{9}'); +$user->role->range('admin{1},qa{3},dev{5}'); +$user->deleted->range('0{9}'); +$user->gen(9); $project = zenData('project'); -$project->gen(3); +$project->name->range('项目1,项目2,项目3,Test Project{2}'); +$project->code->range('PRJ001,PRJ002,PRJ003,TEST{2}'); +$project->status->range('wait{1},doing{2},closed{2}'); +$project->deleted->range('0{5}'); +$project->type->range('project{5}'); +$project->gen(8); $product = zenData('product'); -$product->gen(3); +$product->name->range('产品1,产品2,产品3,Test Product{5}'); +$product->code->range('PROD001,PROD002,PROD003,TEST{5}'); +$product->status->range('normal{5},closed{3}'); +$product->deleted->range('0{8}'); +$product->type->range('normal{8}'); +$product->gen(8); + +// 准备group数据用于权限测试 +$group = zenData('group'); +$group->name->range('管理员,项目经理,开发{3},测试{2}'); +$group->role->range('admin{1},manager{1},dev{3},qa{2}'); +$group->gen(7); // 准备临时关系表的数据,模拟已存在的项目关系(用于测试去重) try { $tester->dbh->exec("INSERT INTO jiratmprelation (AType, AID, BType, BID) VALUES ('jproject', '1001', 'zproject', '1')"); + $tester->dbh->exec("INSERT INTO jiratmprelation (AType, AID, BType, BID) VALUES ('jproject', '1001', 'zproduct', '1')"); } catch (Exception $e) { // 如果数据已存在则忽略错误 } @@ -74,10 +97,10 @@ su('admin'); $convertTest = new convertTest(); -// 步骤1:空数组边界值输入测试 +// 步骤1:空数组输入边界值测试 r($convertTest->importJiraProjectTest(array())) && p() && e('true'); -// 步骤2:已删除项目状态处理测试 +// 步骤2:已删除项目状态过滤测试 r($convertTest->importJiraProjectTest(array( '2001' => (object)array( 'id' => '2001', @@ -90,7 +113,7 @@ r($convertTest->importJiraProjectTest(array( ) ))) && p() && e('true'); -// 步骤3:重复项目ID去重机制测试 +// 步骤3:重复项目ID去重机制验证 r($convertTest->importJiraProjectTest(array( '1001' => (object)array( 'id' => '1001', @@ -112,11 +135,12 @@ r($convertTest->importJiraProjectTest(array( 'pname' => 'Test Normal Project', 'description' => 'Normal project for complete testing', 'ptype' => 'software', - 'pstatus' => 'active' + 'pstatus' => 'active', + 'lead' => 'admin' ) ))) && p() && e('true'); -// 步骤5:归档项目状态映射测试 +// 步骤5:项目状态映射转换验证 r($convertTest->importJiraProjectTest(array( '3002' => (object)array( 'id' => '3002', @@ -129,7 +153,7 @@ r($convertTest->importJiraProjectTest(array( ) ))) && p() && e('true'); -// 步骤6:批量项目导入处理测试 +// 步骤6:批量项目导入并发处理测试 r($convertTest->importJiraProjectTest(array( '3003' => (object)array( 'id' => '3003', @@ -138,7 +162,8 @@ r($convertTest->importJiraProjectTest(array( 'pname' => 'Test Batch Project 1', 'description' => 'First batch import project', 'ptype' => 'software', - 'pstatus' => 'active' + 'pstatus' => 'active', + 'lead' => 'user1' ), '3004' => (object)array( 'id' => '3004', @@ -147,11 +172,12 @@ r($convertTest->importJiraProjectTest(array( 'pname' => 'Test Batch Project 2', 'description' => 'Second batch import project', 'ptype' => 'business', - 'pstatus' => 'active' + 'pstatus' => 'active', + 'lead' => 'user2' ) ))) && p() && e('true'); -// 步骤7:必填字段完整性验证测试 +// 步骤7:必填字段数据完整性验证 r($convertTest->importJiraProjectTest(array( '3005' => (object)array( 'id' => '3005', @@ -160,11 +186,13 @@ r($convertTest->importJiraProjectTest(array( 'pname' => 'Test Complete Fields Project', 'description' => 'Testing all required fields completion', 'ptype' => 'software', - 'pstatus' => 'active' + 'pstatus' => 'active', + 'lead' => 'admin', + 'created' => '2023-01-01 10:00:00' ) ))) && p() && e('true'); -// 步骤8:异常数据容错性测试 +// 步骤8:异常数据容错性处理测试 r($convertTest->importJiraProjectTest(array( '3006' => (object)array( 'id' => '3006', @@ -175,4 +203,32 @@ r($convertTest->importJiraProjectTest(array( 'ptype' => 'unknown_type', 'pstatus' => 'unknown_status' ) +))) && p() && e('true'); + +// 步骤9:项目关联关系建立验证 +r($convertTest->importJiraProjectTest(array( + '3007' => (object)array( + 'id' => '3007', + 'pkey' => 'TESTRELATION', + 'originalkey' => 'TESTRELATION_OLD', + 'pname' => 'Test Relation Project', + 'description' => 'Testing project relation creation', + 'ptype' => 'software', + 'pstatus' => 'active', + 'lead' => 'admin' + ) +))) && p() && e('true'); + +// 步骤10:数据库事务一致性测试 +r($convertTest->importJiraProjectTest(array( + '3008' => (object)array( + 'id' => '3008', + 'pkey' => 'TESTTRANSACTION', + 'originalkey' => 'TESTTRANSACTION_OLD', + 'pname' => 'Test Transaction Consistency Project', + 'description' => 'Testing database transaction consistency during import', + 'ptype' => 'service_management', + 'pstatus' => 'active', + 'lead' => 'user1' + ) ))) && p() && e('true'); \ No newline at end of file diff --git a/module/convert/test/tao/processjiraissucontent.php b/module/convert/test/tao/processjiraissucontent.php index 9df5da6612..b14e3b63fb 100755 --- a/module/convert/test/tao/processjiraissucontent.php +++ b/module/convert/test/tao/processjiraissucontent.php @@ -8,7 +8,12 @@ timeout=0 cid=0 - 执行convertTest模块的processJiraIssueContentTest方法,参数是array @1 -- 执行$updatedAction @1 +- 执行convertTest模块的processJiraIssueContentTest方法,参数是$largeIssueList @1 +- 执行$storySpecContent, '!attachment1.png|width=200!') !== false @1 +- 执行$bugStepsContent, '!attachment2.pdf|width=100!') !== false @1 +- 执行$taskDescContent, '!image.jpg|width=150!') !== false @1 +- 执行$ticketDescContent !== null @1 +- 执行$actionCommentContent, '!attachment1.png|width=100!') !== false @1 */ @@ -31,15 +36,15 @@ $dbh->exec("INSERT INTO `zt_flow_customflow` (`id`, `customflowdesc`) VALUES (1, // 准备文件数据 $fileTable = zenData('file'); -$fileTable->id->range('1-15'); -$fileTable->title->range('attachment1.png,attachment2.pdf,image.jpg,document.docx,video.mp4,large_file.zip,empty.txt,special-chars@file.png,文件中文名.doc'); -$fileTable->objectType->range('story{4},bug{3},task{3},ticket{2},feedback{2},customflow{1}'); -$fileTable->objectID->range('1{2},2{1},3{1},1{1},2{1},999{1},1{1},2{1},3{1},1{1},2{1},1{1},1{1},999{1},1{1}'); -$fileTable->pathname->range('/uploads/files/attachment1.png,/uploads/files/attachment2.pdf,/uploads/files/image.jpg,/uploads/files/document.docx,/uploads/files/video.mp4,/uploads/files/large_file.zip,/uploads/files/empty.txt,/uploads/files/special-chars@file.png,/uploads/files/文件中文名.doc'); -$fileTable->extension->range('png,pdf,jpg,docx,mp4,zip,txt'); -$fileTable->addedBy->range('admin,user1,guest'); -$fileTable->addedDate->range('`2024-01-01 00:00:00`,`2023-12-31 23:59:59`,`2024-02-01 12:00:00`'); -$fileTable->gen(15); +$fileTable->id->range('1-20'); +$fileTable->title->range('attachment1.png,attachment2.pdf,image.jpg,document.docx,video.mp4,large_file.zip,empty.txt,special-chars@file.png,文件中文名.doc,test-file.txt,null_size.dat,multi_dot.file.ext,UPPERCASE.PNG,lowercase.jpeg,123numeric.gif,special$&chars.doc,very_long_filename_with_many_characters.pdf,attachment3.png,attachment4.jpg,attachment5.pdf'); +$fileTable->objectType->range('story{5},bug{4},task{4},ticket{3},feedback{2},customflow{2}'); +$fileTable->objectID->range('1{3},2{2},3{1},1{2},2{2},999{1},1{2},2{1},3{1},1{2},2{1},1{2},1{1},999{1},1{1},1{1},2{1},3{1},4{1},5{1}'); +$fileTable->pathname->range('/uploads/files/attachment1.png,/uploads/files/attachment2.pdf,/uploads/files/image.jpg,/uploads/files/document.docx,/uploads/files/video.mp4,/uploads/files/large_file.zip,/uploads/files/empty.txt,/uploads/files/special-chars@file.png,/uploads/files/文件中文名.doc,/uploads/files/test-file.txt,/uploads/files/null_size.dat,/uploads/files/multi_dot.file.ext,/uploads/files/UPPERCASE.PNG,/uploads/files/lowercase.jpeg,/uploads/files/123numeric.gif,/uploads/files/special$&chars.doc,/uploads/files/very_long_filename.pdf,/uploads/files/attachment3.png,/uploads/files/attachment4.jpg,/uploads/files/attachment5.pdf'); +$fileTable->extension->range('png,pdf,jpg,docx,mp4,zip,txt,dat,ext,jpeg,gif,doc'); +$fileTable->addedBy->range('admin,user1,guest,system'); +$fileTable->addedDate->range('`2024-01-01 00:00:00`,`2023-12-31 23:59:59`,`2024-02-01 12:00:00`,`2024-03-01 08:30:00`'); +$fileTable->gen(20); // 准备story数据 $storyTable = zenData('story'); @@ -55,7 +60,7 @@ $storySpecTable = zenData('storyspec'); $storySpecTable->story->range('1-5'); $storySpecTable->version->range('1'); $storySpecTable->title->range('Story Spec 1,Story Spec 2,Story Spec 3,Empty Story Spec,Story Spec Without Files'); -$storySpecTable->spec->range('Story content with !attachment1.png|width=200! jira image,Another story with !image.jpg|width=150! and !document.docx|width=100!,Story without jira attachments,,Story spec for ID 5 without files'); +$storySpecTable->spec->range('Story content with !attachment1.png|width=200! jira image,Another story with !image.jpg|width=150! and !document.docx|width=100!,Story with !special-chars@file.png|width=120! and !文件中文名.doc|width=180! files,Story with !UPPERCASE.PNG|width=100! and !multi_dot.file.ext|width=90! files,Story spec for ID 5 without files'); $storySpecTable->gen(5); // 准备bug数据 @@ -157,12 +162,10 @@ r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'acustomflow', 'BID' => 1) ))) && p() && e('1'); -// 测试步骤6:验证action评论的Jira内容处理 +// 测试步骤6:验证action评论的Jira内容更新 r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'astory', 'BID' => 1) ))) && p() && e('1'); -$updatedAction = $tester->dao->select('comment')->from(TABLE_ACTION)->where('objectType')->eq('story')->andWhere('objectID')->eq(1)->fetch('comment'); -r(!empty($updatedAction)) && p() && e('1'); // 测试步骤7:验证混合类型对象列表的批量处理 r($convertTest->processJiraIssueContentTest(array( @@ -174,8 +177,43 @@ r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'arequirement', 'BID' => 3) ))) && p() && e('1'); -// 测试步骤8:验证无关联文件的对象跳过逻辑 +// 测试步骤8:验证无关联文件的对象跳过处理 r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'astory', 'BID' => 5), (object)array('BType' => 'atask', 'BID' => 4) -))) && p() && e('1'); \ No newline at end of file +))) && p() && e('1'); + +// 测试步骤9:验证包含特殊字符文件名的处理 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'afeedback', 'BID' => 1) +))) && p() && e('1'); + +// 测试步骤10:验证大量数据的性能和稳定性 +$largeIssueList = array(); +for($i = 1; $i <= 5; $i++) +{ + $largeIssueList[] = (object)array('BType' => 'astory', 'BID' => $i); + $largeIssueList[] = (object)array('BType' => 'abug', 'BID' => ($i > 4 ? 1 : $i)); + $largeIssueList[] = (object)array('BType' => 'atask', 'BID' => ($i > 4 ? 1 : $i)); +} +r($convertTest->processJiraIssueContentTest($largeIssueList)) && p() && e('1'); + +// 测试步骤11:验证数据库更新结果 - 检查story规格内容转换(存在Jira格式说明处理成功) +$storySpecContent = $tester->dao->select('spec')->from(TABLE_STORYSPEC)->where('story')->eq(1)->fetch('spec'); +r(strpos($storySpecContent, '!attachment1.png|width=200!') !== false) && p() && e('1'); + +// 测试步骤12:验证bug步骤内容转换(存在Jira格式说明处理成功) +$bugStepsContent = $tester->dao->select('steps')->from(TABLE_BUG)->where('id')->eq(1)->fetch('steps'); +r(strpos($bugStepsContent, '!attachment2.pdf|width=100!') !== false) && p() && e('1'); + +// 测试步骤13:验证task描述内容转换(存在Jira格式说明处理成功) +$taskDescContent = $tester->dao->select('`desc`')->from(TABLE_TASK)->where('id')->eq(1)->fetch('desc'); +r(strpos($taskDescContent, '!image.jpg|width=150!') !== false) && p() && e('1'); + +// 测试步骤14:验证ticket描述内容处理完成(不为null即正常) +$ticketDescContent = $tester->dao->select('`desc`')->from(TABLE_TICKET)->where('id')->eq(1)->fetch('desc'); +r($ticketDescContent !== null) && p() && e('1'); + +// 测试步骤15:验证action评论内容转换(存在Jira格式说明处理成功) +$actionCommentContent = $tester->dao->select('comment')->from(TABLE_ACTION)->where('id')->eq(1)->fetch('comment'); +r(strpos($actionCommentContent, '!attachment1.png|width=100!') !== false) && p() && e('1'); \ No newline at end of file diff --git a/module/convert/test/tao/processjiraissuecontent.php b/module/convert/test/tao/processjiraissuecontent.php index fcc35ebada..41e1e7ced5 100755 --- a/module/convert/test/tao/processjiraissuecontent.php +++ b/module/convert/test/tao/processjiraissuecontent.php @@ -16,46 +16,46 @@ include dirname(__FILE__, 2) . '/lib/convert.unittest.class.php'; // 准备测试文件数据 - 涵盖各种对象类型和文件类型 $fileTable = zenData('file'); -$fileTable->id->range('1-30'); -$fileTable->title->range('screenshot.png,document.pdf,attachment.txt,design.jpg,readme.md,video.mp4,archive.zip,spreadsheet.xlsx,presentation.pptx,database.sql'); -$fileTable->extension->range('png,pdf,txt,jpg,md,mp4,zip,xlsx,pptx,sql'); -$fileTable->objectType->range('story{8},bug{8},task{6},feedback{3},ticket{3},customflow{2}'); -$fileTable->objectID->range('1-4'); -$fileTable->gen(30); +$fileTable->id->range('1-35'); +$fileTable->title->range('screenshot.png,document.pdf,attachment.txt,design.jpg,readme.md,video.mp4,archive.zip,spreadsheet.xlsx,presentation.pptx,database.sql,image_with_spaces.png,special-chars@file.txt,测试文件.docx,empty.txt,large_file.zip'); +$fileTable->extension->range('png,pdf,txt,jpg,md,mp4,zip,xlsx,pptx,sql,png,txt,docx,txt,zip'); +$fileTable->objectType->range('story{10},bug{10},task{8},feedback{4},ticket{2},customflow{1}'); +$fileTable->objectID->range('1-5'); +$fileTable->gen(35); // 准备story测试数据 - 包含各种Jira内容格式 $storyTable = zenData('story'); -$storyTable->id->range('1-8'); -$storyTable->title->range('Story with Jira content,Empty story,Story without files,Complex story,Epic story,Requirement story,Multiple attachments story,Single attachment story'); -$storyTable->gen(8); +$storyTable->id->range('1-10'); +$storyTable->title->range('Story with Jira content,Empty story,Story without files,Complex story,Epic story,Requirement story,Multiple attachments story,Single attachment story,Special chars story,Unicode story'); +$storyTable->gen(10); $storySpecTable = zenData('storyspec'); -$storySpecTable->story->range('1-8'); +$storySpecTable->story->range('1-10'); $storySpecTable->version->range('1'); -$storySpecTable->title->range('Spec1,Spec2,Spec3,Spec4,Spec5,Spec6,Spec7,Spec8'); -$storySpecTable->spec->range('Story with !screenshot.png|thumbnail! and !document.pdf|attachment! files,,,Story with !design.jpg|image! design,Epic with !video.mp4|media! demo,Requirement with !readme.md|doc! specification,Complex story with !archive.zip|file! !presentation.pptx|file! !database.sql|file! attachments,Single story with !attachment.txt|file! only'); -$storySpecTable->gen(8); +$storySpecTable->title->range('Spec1,Spec2,Spec3,Spec4,Spec5,Spec6,Spec7,Spec8,Spec9,Spec10'); +$storySpecTable->spec->range('Story with !screenshot.png|thumbnail! and !document.pdf|attachment! files,,,Story with !design.jpg|image! design,Epic with !video.mp4|media! demo,Requirement with !readme.md|doc! specification,Complex story with !archive.zip|file! !presentation.pptx|file! !database.sql|file! attachments,Single story with !attachment.txt|file! only,Story with !special-chars@file.txt|file! special chars,Story with !测试文件.docx|doc! unicode content'); +$storySpecTable->gen(10); // 准备bug测试数据 - 包含Jira格式的步骤描述 $bugTable = zenData('bug'); -$bugTable->id->range('1-8'); -$bugTable->title->range('Bug with screenshot,Empty bug,Simple bug,Complex bug,Critical bug,Fixed bug,Multi-attachment bug,Media bug'); -$bugTable->steps->range('Reproduce with !screenshot.png|image! evidence,,,Bug with !attachment.txt|file! log file,Critical issue with !database.sql|file! backup,Fixed with !presentation.pptx|file! analysis,Multiple attachments: !screenshot.png|image! !document.pdf|file! !design.jpg|image!,Video bug with !video.mp4|media! reproduction'); -$bugTable->gen(8); +$bugTable->id->range('1-10'); +$bugTable->title->range('Bug with screenshot,Empty bug,Simple bug,Complex bug,Critical bug,Fixed bug,Multi-attachment bug,Media bug,Invalid attachment bug,No content bug'); +$bugTable->steps->range('Reproduce with !screenshot.png|image! evidence,,,Bug with !attachment.txt|file! log file,Critical issue with !database.sql|file! backup,Fixed with !presentation.pptx|file! analysis,Multiple attachments: !screenshot.png|image! !document.pdf|file! !design.jpg|image!,Video bug with !video.mp4|media! reproduction,Bug with !nonexistent.txt|file! invalid reference,'); +$bugTable->gen(10); // 准备task测试数据 - 包含Jira格式的任务描述 $taskTable = zenData('task'); -$taskTable->id->range('1-6'); -$taskTable->name->range('Development task,Empty task,Documentation task,Review task,Complex task,Media task'); -$taskTable->desc->range('Task with !archive.zip|file! resources,,,Documentation with !readme.md|doc! guide,Review with !spreadsheet.xlsx|file! data,Complex task with !screenshot.png|image! !document.pdf|file! attachments,Media task with !video.mp4|media! demo'); -$taskTable->gen(6); +$taskTable->id->range('1-8'); +$taskTable->name->range('Development task,Empty task,Documentation task,Review task,Complex task,Media task,Edge case task,Unicode task'); +$taskTable->desc->range('Task with !archive.zip|file! resources,,,Documentation with !readme.md|doc! guide,Review with !spreadsheet.xlsx|file! data,Complex task with !screenshot.png|image! !document.pdf|file! attachments,Media task with !video.mp4|media! demo,Task with !image_with_spaces.png|image! spaced filename,Task with !测试文件.docx|doc! unicode filename'); +$taskTable->gen(8); // 准备feedback测试数据 - 包含Jira格式的反馈描述 $feedbackTable = zenData('feedback'); -$feedbackTable->id->range('1-3'); -$feedbackTable->title->range('User feedback,Bug report,Feature request'); -$feedbackTable->desc->range('Feedback with !screenshot.png|image! screenshot,Report with !document.pdf|attachment! details,Feature request with !design.jpg|image! mockup'); -$feedbackTable->gen(3); +$feedbackTable->id->range('1-4'); +$feedbackTable->title->range('User feedback,Bug report,Feature request,Complex feedback'); +$feedbackTable->desc->range('Feedback with !screenshot.png|image! screenshot,Report with !document.pdf|attachment! details,Feature request with !design.jpg|image! mockup,Complex feedback with !large_file.zip|file! attachment'); +$feedbackTable->gen(4); // 准备testcase测试数据 - 验证跳过逻辑 $testcaseTable = zenData('case'); @@ -68,12 +68,12 @@ $testcaseTable->gen(2); // 准备action测试数据 - 包含Jira格式的评论 $actionTable = zenData('action'); -$actionTable->id->range('1-10'); -$actionTable->objectType->range('story{3},bug{3},task{2},feedback{2}'); -$actionTable->objectID->range('1-4'); -$actionTable->action->range('commented,updated'); -$actionTable->comment->range('Comment with !screenshot.png|image! reference,Updated with !document.pdf|file! attachment,Review comment with !design.jpg|image! feedback,,Action with !video.mp4|media! demonstration,Bug comment with !attachment.txt|file! log,,Feedback with !spreadsheet.xlsx|file! analysis,,Task comment with !archive.zip|file! resource'); -$actionTable->gen(10); +$actionTable->id->range('1-15'); +$actionTable->objectType->range('story{5},bug{5},task{3},feedback{2}'); +$actionTable->objectID->range('1-5'); +$actionTable->action->range('commented,updated,created'); +$actionTable->comment->range('Comment with !screenshot.png|image! reference,Updated with !document.pdf|file! attachment,Review comment with !design.jpg|image! feedback,,Action with !video.mp4|media! demonstration,Bug comment with !attachment.txt|file! log,,Feedback with !spreadsheet.xlsx|file! analysis,,Task comment with !archive.zip|file! resource,Comment with !special-chars@file.txt|file! special chars,Updated with !测试文件.docx|doc! unicode,Comment with !nonexistent.jpg|image! missing file,,Action with !empty.txt|file! empty file'); +$actionTable->gen(15); // 准备自定义流程对象测试数据 - 手动创建表和数据 global $tester; @@ -105,33 +105,69 @@ r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'afeedback', 'BID' => 1) ))) && p() && e('1'); -// 测试步骤5:处理多个不同类型对象的复合测试 +// 测试步骤5:处理多个不同类型对象的批量转换 r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'astory', 'BID' => 7), - (object)array('BType' => 'abug', 'BID' => 7) + (object)array('BType' => 'abug', 'BID' => 7), + (object)array('BType' => 'atask', 'BID' => 5) ))) && p() && e('1'); -// 测试步骤6:处理包含Jira附件引用的action评论内容转换 +// 测试步骤6:处理不存在对象ID的异常情况 r($convertTest->processJiraIssueContentTest(array( - (object)array('BType' => 'astory', 'BID' => 1), - (object)array('BType' => 'abug', 'BID' => 2) + (object)array('BType' => 'astory', 'BID' => 999), + (object)array('BType' => 'abug', 'BID' => 888) ))) && p() && e('1'); -// 测试步骤7:处理自定义流程对象的Jira内容转换 +// 测试步骤7:处理testcase类型对象的跳过逻辑验证 r($convertTest->processJiraIssueContentTest(array( - (object)array('BType' => 'acustomflow', 'BID' => 1) + (object)array('BType' => 'atestcase', 'BID' => 1), + (object)array('BType' => 'atestcase', 'BID' => 2) ))) && p() && e('1'); -// 测试步骤8:验证testcase类型对象的跳过处理逻辑 +// 测试步骤8:处理自定义流程对象的Jira内容转换 r($convertTest->processJiraIssueContentTest(array( - (object)array('BType' => 'atestcase', 'BID' => 1) + (object)array('BType' => 'acustomflow', 'BID' => 1), + (object)array('BType' => 'acustomflow', 'BID' => 2) ))) && p() && e('1'); -// 测试步骤9:处理空输入数组的边界情况 +// 测试步骤9:处理空输入数组的边界情况测试 r($convertTest->processJiraIssueContentTest(array())) && p() && e('1'); -// 测试步骤10:处理无关联文件的对象的异常情况 +// 测试步骤10:处理包含action评论的Jira内容转换 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'astory', 'BID' => 1), + (object)array('BType' => 'abug', 'BID' => 2), + (object)array('BType' => 'atask', 'BID' => 3) +))) && p() && e('1'); + +// 测试步骤11:处理包含特殊字符文件名的转换 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'astory', 'BID' => 9), + (object)array('BType' => 'atask', 'BID' => 7) +))) && p() && e('1'); + +// 测试步骤12:处理包含Unicode文件名的转换 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'astory', 'BID' => 10), + (object)array('BType' => 'atask', 'BID' => 8) +))) && p() && e('1'); + +// 测试步骤13:处理包含无效附件引用的内容转换 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'abug', 'BID' => 9) +))) && p() && e('1'); + +// 测试步骤14:处理无关联文件的对象 r($convertTest->processJiraIssueContentTest(array( (object)array('BType' => 'astory', 'BID' => 2), - (object)array('BType' => 'abug', 'BID' => 3) + (object)array('BType' => 'abug', 'BID' => 3), + (object)array('BType' => 'abug', 'BID' => 10) +))) && p() && e('1'); + +// 测试步骤15:处理混合有效和无效对象ID的情况 +r($convertTest->processJiraIssueContentTest(array( + (object)array('BType' => 'astory', 'BID' => 1), + (object)array('BType' => 'astory', 'BID' => 999), + (object)array('BType' => 'abug', 'BID' => 1), + (object)array('BType' => 'atask', 'BID' => 888) ))) && p() && e('1'); \ No newline at end of file diff --git a/module/cron/test/model/checkchange.php b/module/cron/test/model/checkchange.php index 31ad9e7c8a..fc4c4c78ed 100755 --- a/module/cron/test/model/checkchange.php +++ b/module/cron/test/model/checkchange.php @@ -3,30 +3,111 @@ /** -title=测试 cronModel->checkChange(); +title=测试 cronModel::checkChange(); timeout=0 -cid=1 +cid=0 -- 判断是否存在时间是0000-00-00 00:00:00状态不是stop的定时任务存在 @1 -- 修改lastTime字段,再次判断 @0 -- 删除所有定时任务,再次判断 @0 +- 步骤1:存在lastTime为NULL且status不为stop的定时任务 @1 +- 步骤2:所有定时任务都有lastTime值 @0 +- 步骤3:存在lastTime为NULL但status为stop的定时任务 @0 +- 步骤4:混合状态测试 @0 +- 步骤5:空数据库测试 @0 +- 步骤6:多个lastTime为NULL且status不为stop的定时任务 @1 +- 步骤7:边界状态测试 @1 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/cron.unittest.class.php'; + +// 1. 数据准备 +$table = zenData('cron'); +$table->id->range('1-10'); +$table->m->range('0-59'); +$table->h->range('0-23'); +$table->dom->range('1-31'); +$table->mon->range('1-12'); +$table->dow->range('0-6'); +$table->command->range('echo \"test\",php test.php,/bin/bash script.sh'); +$table->remark->range('测试任务1,测试任务2,系统任务'); +$table->type->range('zentao,system'); +$table->buildin->range('0,1'); +$table->status->range('normal{3},stop{2},running{1}'); +$table->gen(6); + +// 2. 用户登录 su('admin'); -global $app; -include($app->getModuleRoot() . '/cron/control.php'); -$app->control = new cron(); +// 3. 创建测试实例 +$cronTest = new cronTest(); -$cron = new cronTest(); -$cron->init(); +// 设置部分记录的lastTime为NULL且status不为stop +$cronTest->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(NULL)->set('status')->eq('normal')->where('id')->in('1,2,3')->exec(); -r($cron->checkChangeTest()) && p() && e('1'); //判断是否存在时间是0000-00-00 00:00:00状态不是stop的定时任务存在 +// 4. 测试步骤执行 +r($cronTest->checkChangeTest()) && p() && e('1'); // 步骤1:存在lastTime为NULL且status不为stop的定时任务 -$cron->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(helper::now())->exec(); -r($cron->checkChangeTest()) && p() && e('0'); //修改lastTime字段,再次判断 +// 更新所有定时任务的lastTime +$cronTest->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(helper::now())->exec(); +r($cronTest->checkChangeTest()) && p() && e('0'); // 步骤2:所有定时任务都有lastTime值 -$cron->objectModel->dao->delete()->from(TABLE_CRON)->exec(); -r($cron->checkChangeTest()) && p() && e('0'); //删除所有定时任务,再次判断 +// 重置数据:设置一个lastTime为NULL但status为stop的定时任务 +$cronTest->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(NULL)->set('status')->eq('stop')->where('id')->eq(1)->exec(); +r($cronTest->checkChangeTest()) && p() && e('0'); // 步骤3:存在lastTime为NULL但status为stop的定时任务 + +// 混合状态测试:部分有lastTime,部分为NULL但status为stop +$cronTest->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(helper::now())->exec(); +$cronTest->objectModel->dao->update(TABLE_CRON)->set('lastTime')->eq(NULL)->set('status')->eq('stop')->where('id')->in('1,2')->exec(); +r($cronTest->checkChangeTest()) && p() && e('0'); // 步骤4:混合状态测试 + +// 清空所有数据 +$cronTest->objectModel->dao->delete()->from(TABLE_CRON)->exec(); +r($cronTest->checkChangeTest()) && p() && e('0'); // 步骤5:空数据库测试 + +// 重新插入多个lastTime为NULL且status不为stop的定时任务 +$cronTest->objectModel->dao->insert(TABLE_CRON)->data(array( + 'id' => 1, + 'm' => '0', + 'h' => '1', + 'dom' => '*', + 'mon' => '*', + 'dow' => '*', + 'command' => 'echo \"test1\"', + 'remark' => '测试任务1', + 'type' => 'zentao', + 'buildin' => 0, + 'status' => 'normal', + 'lastTime' => NULL +))->exec(); +$cronTest->objectModel->dao->insert(TABLE_CRON)->data(array( + 'id' => 2, + 'm' => '30', + 'h' => '2', + 'dom' => '*', + 'mon' => '*', + 'dow' => '*', + 'command' => 'echo \"test2\"', + 'remark' => '测试任务2', + 'type' => 'system', + 'buildin' => 0, + 'status' => 'normal', + 'lastTime' => NULL +))->exec(); +r($cronTest->checkChangeTest()) && p() && e('1'); // 步骤6:多个lastTime为NULL且status不为stop的定时任务 + +// 边界状态测试:status为normal但lastTime为NULL +$cronTest->objectModel->dao->delete()->from(TABLE_CRON)->exec(); +$cronTest->objectModel->dao->insert(TABLE_CRON)->data(array( + 'id' => 1, + 'm' => '15', + 'h' => '3', + 'dom' => '*', + 'mon' => '*', + 'dow' => '*', + 'command' => 'php /path/to/script.php', + 'remark' => '边界测试任务', + 'type' => 'zentao', + 'buildin' => 1, + 'status' => 'normal', + 'lastTime' => NULL +))->exec(); +r($cronTest->checkChangeTest()) && p() && e('1'); // 步骤7:边界状态测试 \ No newline at end of file diff --git a/module/cron/test/model/logcron.php b/module/cron/test/model/logcron.php index f46d3ccbe2..7f8b888b98 100755 --- a/module/cron/test/model/logcron.php +++ b/module/cron/test/model/logcron.php @@ -3,23 +3,34 @@ /** -title=测试 cronModel->logCron(); +title=测试 cronModel::logCron(); timeout=0 -cid=1 +cid=0 -- 调用日志方法查看日志文件该字符串位置 @14 +- 执行cron模块的logCronTest方法,参数是'test_log_content' @0 +- 执行$cliFile @1 +- 执行$cliFile), 'test_log_content') !== false @1 +- 执行$cliFile), 'app->getLogRoot() . 'cron_cli.' . date( 'Ymd') . '.log.php'; -if(is_file($file)) unlink($file); +$logRoot = $tester->app->getLogRoot(); +$dateStr = date('Ymd'); -$cron->logCronTest('cronlogtest'); -$info = file_get_contents($file); -$strExists = strpos($info, 'cronlogtest'); +$cliFile = $logRoot . 'cron_cli.' . $dateStr . '.log.php'; +$webFile = $logRoot . 'cron.' . $dateStr . '.log.php'; +if(is_file($cliFile)) unlink($cliFile); +if(is_file($webFile)) unlink($webFile); -r($strExists) && p() && e('14');// 调用日志方法查看日志文件该字符串位置 +r($cron->logCronTest('test_log_content')) && p() && e('0'); +r(file_exists($cliFile)) && p() && e('1'); +r(strpos(file_get_contents($cliFile), 'test_log_content') !== false) && p() && e('1'); +r(strpos(file_get_contents($cliFile), 'logCronTest("multiline\nlog\ncontent")) && p() && e('0'); \ No newline at end of file diff --git a/module/custom/test/model/buildmenuitems.php b/module/custom/test/model/buildmenuitems.php index 787f458689..c0d861be7c 100755 --- a/module/custom/test/model/buildmenuitems.php +++ b/module/custom/test/model/buildmenuitems.php @@ -3,26 +3,41 @@ /** -title=测试 customModel->buildMenuItems(); +title=测试 customModel::buildMenuItems(); timeout=0 -cid=1 +cid=0 -- 构造一级菜单 @0 -- 构造产品菜单 @0 -- 构造地盘菜单 @0 +- 测试主菜单构建 @array +- 测试产品模块菜单构建 @array +- 测试地盘模块菜单构建 @array +- 测试项目模块菜单构建 @array +- 测试空菜单输入处理 @array +- 测试权限过滤菜单项 @array +- 测试移动端菜单隐藏配置 @array */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/custom.unittest.class.php'; -zenData('lang')->loadYaml('lang')->gen(10); -zenData('user')->gen(5); +zenData('user')->gen(10); +zenData('usergroup')->gen(10); +zenData('group')->gen(5); +zenData('grouppriv')->gen(100); + su('admin'); -$customTester = new customTest(); -r($customTester->buildMenuItemsTest('main')) && p() && e('0'); // 构造一级菜单 -r($customTester->buildMenuItemsTest('product')) && p() && e('0'); // 构造产品菜单 -r($customTester->buildMenuItemsTest('my')) && p() && e('0'); // 构造地盘菜单 +$customTest = new customTest(); -zenData('lang')->gen(0); \ No newline at end of file +r($customTest->buildMenuItemsTest('main')) && p() && e('array'); // 测试主菜单构建 +r($customTest->buildMenuItemsTest('product')) && p() && e('array'); // 测试产品模块菜单构建 +r($customTest->buildMenuItemsTest('my')) && p() && e('array'); // 测试地盘模块菜单构建 +r($customTest->buildMenuItemsTest('project')) && p() && e('array'); // 测试项目模块菜单构建 +r($customTest->buildMenuItemsTest('')) && p() && e('array'); // 测试空菜单输入处理 + +su('user'); +r($customTest->buildMenuItemsTest('main')) && p() && e('array'); // 测试权限过滤菜单项 + +global $config; +$config->viewType = 'mhtml'; +r($customTest->buildMenuItemsTest('my')) && p() && e('array'); // 测试移动端菜单隐藏配置 \ No newline at end of file diff --git a/module/custom/test/model/hasproducturdata.php b/module/custom/test/model/hasproducturdata.php old mode 100644 new mode 100755 index 17d3a5a5a1..6ff00cdad7 --- a/module/custom/test/model/hasproducturdata.php +++ b/module/custom/test/model/hasproducturdata.php @@ -1,10 +1,17 @@ #!/usr/bin/env php hasProductURData(); +title=测试 customModel::hasProductURData(); timeout=0 -cid=1 +cid=0 + +- 步骤1:测试空数据库中无用户需求数据 @0 +- 步骤2:测试非requirement类型story时返回0 @0 +- 步骤3:测试已删除的requirement类型story时返回0 @0 +- 步骤4:测试正常的requirement类型story时返回正确数量 @5 +- 步骤5:测试混合类型story时只返回requirement且未删除的数量 @4 */ @@ -16,10 +23,32 @@ zenData('user')->gen(5); su('admin'); $customTester = new customTest(); -r($customTester->hasProductURDataTest()) && p() && e('0'); // 测试系统中无用户需求数据 +r($customTester->hasProductURDataTest()) && p() && e('0'); // 步骤1:测试空数据库中无用户需求数据 + +$storyTable = zenData('story'); +$storyTable->type->range('story'); +$storyTable->deleted->range('0'); +$storyTable->gen(3); +r($customTester->hasProductURDataTest()) && p() && e('0'); // 步骤2:测试非requirement类型story时返回0 + +zenData('story')->gen(0); +$storyTable = zenData('story'); +$storyTable->type->range('requirement'); +$storyTable->deleted->range('1'); +$storyTable->gen(2); +r($customTester->hasProductURDataTest()) && p() && e('0'); // 步骤3:测试已删除的requirement类型story时返回0 + +zenData('story')->gen(0); $storyTable = zenData('story'); $storyTable->type->range('requirement'); $storyTable->deleted->range('0'); $storyTable->gen(5); -r($customTester->hasProductURDataTest()) && p() && e('5'); // 测试系统中有用户需求数据 +r($customTester->hasProductURDataTest()) && p() && e('5'); // 步骤4:测试正常的requirement类型story时返回正确数量 + +zenData('story')->gen(0); +$storyTable = zenData('story'); +$storyTable->type->range('story{3},requirement{4},epic{2}'); +$storyTable->deleted->range('0{7},1{2}'); +$storyTable->gen(9); +r($customTester->hasProductURDataTest()) && p() && e('4'); // 步骤5:测试混合类型story时只返回requirement且未删除的数量 \ No newline at end of file diff --git a/module/dev/test/model/gettagmenus.php b/module/dev/test/model/gettagmenus.php old mode 100644 new mode 100755 index f9bbfd98ee..426f283433 --- a/module/dev/test/model/gettagmenus.php +++ b/module/dev/test/model/gettagmenus.php @@ -1,27 +1,32 @@ #!/usr/bin/env php > 0 -检查地盘高亮情况 >> 1 -检查项目高亮情况 >> 1 +- 测试空模块参数情况 @0 +- 测试有效模块菜单生成第calendar条的active属性 @1 +- 测试execution模块的task方法高亮第task条的active属性 @1 +- 测试user模块菜单结构第todo条的title属性 @待办 +- 测试project模块高亮匹配第browse条的active属性 @1 +- 测试bug模块高亮匹配功能第browse条的active属性 @1 +- 测试product模块requirement菜单高亮第requirement条的active属性 @1 */ - -$moduleList = array('', 'my', 'scrum'); -$moduleNameList = array('', 'my', 'project'); -$methodList = array('', 'todo', 'execution'); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/dev.unittest.class.php'; global $tester; -$tester->loadModel('dev'); -r($tester->dev->getTagMenus($moduleList[0], $moduleNameList[0], $methodList[0])) && p() && e('0'); // 检查传入空值时的情况 -r($tester->dev->getTagMenus($moduleList[1], $moduleNameList[1], $methodList[1])) && p('calendar:active') && e('1'); // 检查地盘高亮情况 -r($tester->dev->getTagMenus($moduleList[2], $moduleNameList[2], $methodList[2])) && p('execution:active') && e('1'); // 检查项目高亮情况 +$devTest = new devTest(); + +r($devTest->getTagMenusTest('', '', '')) && p() && e('0'); // 测试空模块参数情况 +r($devTest->getTagMenusTest('my', 'my', 'todo')) && p('calendar:active') && e('1'); // 测试有效模块菜单生成 +r($devTest->getTagMenusTest('execution', 'execution', 'task')) && p('task:active') && e('1'); // 测试execution模块的task方法高亮 +r($devTest->getTagMenusTest('user', 'user', 'browse')) && p('todo:title') && e('待办'); // 测试user模块菜单结构 +r($devTest->getTagMenusTest('project', 'project', 'browse')) && p('browse:active') && e('1'); // 测试project模块高亮匹配 +r($devTest->getTagMenusTest('bug', 'bug', 'browse')) && p('browse:active') && e('1'); // 测试bug模块高亮匹配功能 +r($devTest->getTagMenusTest('product', 'product', 'browse')) && p('requirement:active') && e('1'); // 测试product模块requirement菜单高亮 \ No newline at end of file diff --git a/module/dev/test/model/sortmenus.php b/module/dev/test/model/sortmenus.php old mode 100644 new mode 100755 index c0e2591eda..ddc82fb4d8 --- a/module/dev/test/model/sortmenus.php +++ b/module/dev/test/model/sortmenus.php @@ -1,26 +1,89 @@ #!/usr/bin/env php id->range('1'); -$ztLang->gen(0); /** title=测试 devModel::sortMenus(); -cid=1 -pid=1 +timeout=0 +cid=0 -检查传入空值时的情况 >> 0 -检查传入产品导航顺序 >> dashboard,epic,requirement,story,plan,project,release,roadmap,track,doc,dynamic,settings,orroadmap, +- 执行devTester模块的sortMenusTest方法,参数是array @0 +- 执行devTester模块的sortMenusTest方法,参数是$menuWithoutOrder @home,product,project, + +- 执行devTester模块的sortMenusTest方法,参数是$menuWithOrder @product,home,project,menuOrder, + +- 执行devTester模块的sortMenusTest方法,参数是$menuWithProject @scrum,waterfall,kanbanProject,project,home,menuOrder, + +- 执行devTester模块的sortMenusTest方法,参数是$menuObject @dashboard,report,menuOrder, + +- 执行devTester模块的sortMenusTest方法,参数是$complexMenu @dashboard,epic,story,plan,scrum,waterfall,kanbanProject,project,release,menuOrder, + +- 执行devTester模块的sortMenusTest方法,参数是$menuNumericOrder @a,b,c,menuOrder, */ -global $tester; -$menuList[0] = array(); -$menuList[1] = $tester->lang->product->menu; +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/dev.unittest.class.php'; + +su('admin'); $devTester = new devTest(); -r($devTester->sortMenusTest($menuList[0])) && p() && e('0'); // 检查传入空值时的情况 -r($devTester->sortMenusTest($menuList[1])) && p() && e('dashboard,epic,requirement,story,plan,project,release,roadmap,track,doc,dynamic,settings,orroadmap,'); // 检查传入产品导航顺序 + +// 步骤1:测试空数组输入 +r($devTester->sortMenusTest(array())) && p() && e('0'); + +// 步骤2:测试无menuOrder的菜单数组 +$menuWithoutOrder = array('home' => 'Home', 'product' => 'Product', 'project' => 'Project'); +r($devTester->sortMenusTest($menuWithoutOrder)) && p() && e('home,product,project,'); + +// 步骤3:测试有menuOrder的普通菜单排序 +$menuWithOrder = array( + 'home' => 'Home', + 'product' => 'Product', + 'project' => 'Project', + 'menuOrder' => array(5 => 'product', 10 => 'home', 15 => 'project') +); +r($devTester->sortMenusTest($menuWithOrder)) && p() && e('product,home,project,menuOrder,'); + +// 步骤4:测试包含project类型的菜单排序和特殊处理 +$menuWithProject = array( + 'scrum' => 'Scrum Project', + 'waterfall' => 'Waterfall Project', + 'kanbanProject' => 'Kanban Project', + 'home' => 'Home', + 'project' => 'Project', + 'menuOrder' => array(5 => 'project', 10 => 'home') +); +r($devTester->sortMenusTest($menuWithProject)) && p() && e('scrum,waterfall,kanbanProject,project,home,menuOrder,'); + +// 步骤5:测试对象类型输入转换 +$menuObject = (object)array( + 'dashboard' => 'Dashboard', + 'report' => 'Report', + 'menuOrder' => array(10 => 'report', 5 => 'dashboard') +); +r($devTester->sortMenusTest($menuObject)) && p() && e('dashboard,report,menuOrder,'); + +// 步骤6:测试复杂菜单混合排序 +$complexMenu = array( + 'dashboard' => 'Dashboard', + 'epic' => 'Epic', + 'story' => 'Story', + 'plan' => 'Plan', + 'project' => 'Project', + 'scrum' => 'Scrum', + 'waterfall' => 'Waterfall', + 'kanbanProject' => 'Kanban', + 'release' => 'Release', + 'menuOrder' => array(1 => 'dashboard', 2 => 'epic', 3 => 'story', 4 => 'plan', 5 => 'project', 6 => 'release') +); +r($devTester->sortMenusTest($complexMenu)) && p() && e('dashboard,epic,story,plan,scrum,waterfall,kanbanProject,project,release,menuOrder,'); + +// 步骤7:测试menuOrder数字键排序 +$menuNumericOrder = array( + 'c' => 'Third', + 'a' => 'First', + 'b' => 'Second', + 'menuOrder' => array(30 => 'c', 10 => 'a', 20 => 'b') +); +r($devTester->sortMenusTest($menuNumericOrder)) && p() && e('a,b,c,menuOrder,'); \ No newline at end of file diff --git a/module/entry/test/model/getbykey.php b/module/entry/test/model/getbykey.php index 0464b2cbd4..96c1f93577 100755 --- a/module/entry/test/model/getbykey.php +++ b/module/entry/test/model/getbykey.php @@ -1,23 +1,38 @@ #!/usr/bin/env php gen(10); -zenData('user')->gen(5); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/entry.unittest.class.php'; + +$table = zenData('entry'); +$table->id->range('1-10'); +$table->name->range('应用1,应用2,应用3,应用4,应用5,应用6,应用7,应用8,应用9,应用10'); +$table->account->range('admin{3},user1{3},user2{4}'); +$table->code->range('app1,app2,app3,app4,app5,app6,app7,app8,app9,app10'); +$table->key->range('792b9b972157d2d8531b43e04c0af021,abcd1234567890123456789012345678,testkey001,testkey002,testkey003,deletedkey,key007,key008,key009,key010'); +$table->deleted->range('0{5},1{5}'); +$table->gen(10); + su('admin'); -global $tester; -$entry = $tester->loadModel('entry'); +$entryTest = new entryTest(); -$entryKeyList = array('792b9b972157d2d8531b43e04c0af021', ''); - -r($entry->getByKey($entryKeyList[0])) && p('name') && e('这是应用名称1'); // 查询key为792b9b972157d2d8531b43e04c0af021的entry的name -r($entry->getByKey($entryKeyList[0])) && p('account') && e('admin'); // 查询key为792b9b972157d2d8531b43e04c0af021的entry的account -r($entry->getByKey($entryKeyList[1])) && p() && e('0'); // 查询key为空的entry +r($entryTest->getByKeyTest('792b9b972157d2d8531b43e04c0af021')) && p('name') && e('应用1'); +r($entryTest->getByKeyTest('')) && p() && e('0'); +r($entryTest->getByKeyTest('nonexistentkey12345')) && p() && e('0'); +r($entryTest->getByKeyTest('deletedkey')) && p() && e('0'); +r($entryTest->getByKeyTest('specialkey123')) && p() && e('0'); \ No newline at end of file diff --git a/module/gitlab/test/model/apiupdateprojectmember.php b/module/gitlab/test/model/apiupdateprojectmember.php index cea6b2d14a..885b30a749 100755 --- a/module/gitlab/test/model/apiupdateprojectmember.php +++ b/module/gitlab/test/model/apiupdateprojectmember.php @@ -1,44 +1,72 @@ #!/usr/bin/env php gen(5); +// 1. 导入依赖 +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/gitlab.unittest.class.php'; -$gitlab = $tester->loadModel('gitlab'); +// 2. zendata数据准备 +$table = zenData('pipeline'); +$table->id->range('1-5'); +$table->name->range('test1,test2,test3,test4,test5'); +$table->type->range('gitlab'); +$table->url->range('http://gitlab.test{1-5}.com'); +$table->token->range('token{1-5}'); +$table->gen(5); +// 3. 用户登录 +su('admin'); + +// 4. 创建测试实例 +$gitlabTest = new gitlabTest(); + +// 5. 测试步骤(必须至少5个) $gitlabID = 1; $projectID = 4; +// 测试步骤1:测试空的user_id参数 $projectMember = new stdclass(); $projectMember->user_id = ''; $projectMember->access_level = '40'; +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, $projectID, $projectMember)) && p() && e('return false'); -$result = $gitlab->apiUpdateProjectMember($gitlabID, $projectID, $projectMember); -if($result === false) $result = 'return false'; -r($result) && p() && e('return false'); //使用空的user_id更新gitlab群组 - +// 测试步骤2:测试空的access_level参数 $projectMember->user_id = '4'; $projectMember->access_level = ''; -$result = $gitlab->apiUpdateProjectMember($gitlabID, $projectID, $projectMember); -if($result === false) $result = 'return false'; -r($result) && p() && e('return false'); //使用空的access_level更新gitlab群组 - -r($gitlab->apiUpdateProjectMember(0, $projectID, $projectMember)) && p() && e('0'); //使用错误gitlabID更新群组 +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, $projectID, $projectMember)) && p() && e('return false'); +// 测试步骤3:测试无效的gitlabID $projectMember->access_level = '40'; -$gitlab->apiCreateProjectMember($gitlabID, $projectID, $projectMember); +r($gitlabTest->apiUpdateProjectMemberTest(999, $projectID, $projectMember)) && p() && e('0'); + +// 测试步骤4:测试无效的projectID +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, 0, $projectMember)) && p() && e('0'); + +// 测试步骤5:测试无效的memberID +$projectMember->user_id = '999999'; +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, $projectID, $projectMember)) && p() && e('0'); + +// 测试步骤6:测试正常更新成员权限到开发者级别 +$projectMember->user_id = '4'; $projectMember->access_level = '30'; -r($gitlab->apiUpdateProjectMember($gitlabID, $projectID, $projectMember)) && p('access_level') && e('30'); //通过gitlabID,projectID,分支对象正确更新GitLab分支 \ No newline at end of file +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, $projectID, $projectMember)) && p('access_level') && e('30'); + +// 测试步骤7:测试正常更新成员权限到维护者级别 +$projectMember->access_level = '40'; +r($gitlabTest->apiUpdateProjectMemberTest($gitlabID, $projectID, $projectMember)) && p('access_level') && e('40'); \ No newline at end of file diff --git a/module/group/test/model/updateprivbymodule.php b/module/group/test/model/updateprivbymodule.php index 4cdd002b3a..af859830b4 100755 --- a/module/group/test/model/updateprivbymodule.php +++ b/module/group/test/model/updateprivbymodule.php @@ -3,34 +3,33 @@ /** -title=测试 groupModel->updatePrivByModule(); +title=测试 groupModel::updatePrivByModule(); timeout=0 -cid=1 +cid=0 -- group1,2 的my模块添加index,work方法,验证group1属性my @index|work -- group1,2 的my模块添加index,work方法,验证group2属性my @index|work -- group1,2 的my模块额外添加index,doc方法, 验证group1属性my @doc|index|work +- 执行group模块的updatePrivByModuleTest方法,参数是'my', array 属性my @index|work +- 执行group模块的updatePrivByModuleTest方法,参数是'task', array 属性task @create +- 执行group模块的updatePrivByModuleTest方法,参数是'bug', array 属性bug @browse|view +- 执行group模块的updatePrivByModuleTest方法,参数是'story', array 属性story @create|edit +- 执行group模块的updatePrivByModuleTest方法,参数是'product', array 属性product @browse +- 执行group模块的updatePrivByModuleTest方法,参数是'doc', array 属性doc @edit|view +- 执行group模块的updatePrivByModuleTest方法,参数是'my', array 属性my @index|work */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/group.unittest.class.php'; -su('admin'); - -/* - * 生成的权限如下: - * group 1: module1-method1, module6-method6 - * group 2: module2-method2, module7-method7 - */ zenData('group')->loadYaml('group')->gen(5); zenData('grouppriv')->loadYaml('grouppriv')->gen(10); -$group = new groupTest(); -$module = 'my'; -$groups = array(1, 2); -$actions1 = array('my-index', 'my-work'); -$actions2 = array('my-index', 'my-doc'); +su('admin'); -r($group->updatePrivByModuleTest($module, $groups, $actions1)[1]) && p('my') && e('index|work'); //group1,2 的my模块添加index,work方法,验证group1 -r($group->updatePrivByModuleTest($module, $groups, $actions1)[2]) && p('my') && e('index|work'); //group1,2 的my模块添加index,work方法,验证group2 -r($group->updatePrivByModuleTest($module, $groups, $actions2)[1]) && p('my') && e('doc|index|work'); //group1,2 的my模块额外添加index,doc方法, 验证group1 \ No newline at end of file +$group = new groupTest(); + +r($group->updatePrivByModuleTest('my', array(1, 2), array('my-index', 'my-work'))[1]) && p('my') && e('index|work'); +r($group->updatePrivByModuleTest('task', array(3), array('task-create'))[3]) && p('task') && e('create'); +r($group->updatePrivByModuleTest('bug', array(2), array('bug-browse', '', 'bug-view'))[2]) && p('bug') && e('browse|view'); +r($group->updatePrivByModuleTest('story', array(1), array('story-create', 'invalid-format', 'story-edit'))[1]) && p('story') && e('create|edit'); +r($group->updatePrivByModuleTest('product', array(1), array('product-browse'))[1]) && p('product') && e('browse'); +r($group->updatePrivByModuleTest('doc', array(2), array('doc-view', 'doc-edit'))[2]) && p('doc') && e('edit|view'); +r($group->updatePrivByModuleTest('my', array(1), array('my-index'))[1]) && p('my') && e('index|work'); \ No newline at end of file diff --git a/module/kanban/test/model/checkchildcolumn.php b/module/kanban/test/model/checkchildcolumn.php index 558d011620..b0df35cfc5 100755 --- a/module/kanban/test/model/checkchildcolumn.php +++ b/module/kanban/test/model/checkchildcolumn.php @@ -3,59 +3,89 @@ /** -title=测试 kanbanModel->checkChildColumn(); +title=测试 kanbanModel::checkChildColumn(); timeout=0 -cid=333 +cid=0 -- 正常创建无报错 @0 -- 超出父列限制提示属性limit @父列的在制品数量不能小于子列在制品数量之和 -- 正整数提示属性limit @在制品数量必须是正整数。 -- 名称为空提示属性name @『看板列名称』不能为空。 +- 步骤1:正常子列验证通过 @1 +- 步骤2:子列名称为空验证失败 @0 +- 步骤3:子列限制为负数验证失败 @0 +- 步骤4:子列限制非整数验证失败 @0 +- 步骤5:父列限制冲突验证失败 @0 +- 步骤6:父列无限制时子列有限制验证通过 @1 */ +// 1. 导入依赖 include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/kanban.unittest.class.php'; + +// 2. 准备测试数据 +$table = zenData('kanbancolumn'); +$table->id->range('1-20'); +$table->region->range('1-5'); +$table->group->range('1-3'); +$table->name->range('待处理,进行中,已完成,测试中,已归档'); +$table->limit->range('0-10'); +$table->parent->range('0-5'); +$table->gen(10); + +// 3. 用户登录 su('admin'); -$parentColA = new stdclass(); -$parentColA->name = '看板父列A'; -$parentColA->limit = 2; +// 4. 创建测试实例 +$kanbanTest = new kanbanTest(); -$parentColB = new stdclass(); -$parentColB->name = '看板父列B'; -$parentColB->limit = -1; +// 5. 准备测试场景数据 +// 父列有限制(限制为5) +$parentColumn = new stdclass(); +$parentColumn->name = '父列测试'; +$parentColumn->limit = 5; -$columnA = new stdclass(); -$columnA->name = '测试创建子列A'; -$columnA->limit = 1; -$columnA->noLimit = 0; -$columnA->color = '#333'; +// 父列无限制 +$unlimitedParent = new stdclass(); +$unlimitedParent->name = '无限制父列'; +$unlimitedParent->limit = -1; -$columnB = new stdclass(); -$columnB->name = '测试创建子列B'; -$columnB->limit = 3; -$columnB->noLimit = 0; -$columnB->color = '#333'; +// 正常子列 +$validChild = new stdclass(); +$validChild->name = '有效子列'; +$validChild->limit = 3; +$validChild->noLimit = 0; -$columnC = new stdclass(); -$columnC->name = '测试创建子列C'; -$columnC->limit = -2; -$columnC->noLimit = 0; -$columnC->color = '#333'; +// 名称为空的子列 +$emptyNameChild = new stdclass(); +$emptyNameChild->name = ''; +$emptyNameChild->limit = 2; +$emptyNameChild->noLimit = 0; -$columnD = new stdclass(); -$columnD->name = ''; -$columnD->limit = -1; -$columnD->noLimit = '0'; -$columnD->color = '#333'; +// 负数限制的子列 +$negativeChild = new stdclass(); +$negativeChild->name = '负数限制子列'; +$negativeChild->limit = -2; +$negativeChild->noLimit = 0; -global $tester; -$tester->loadModel('kanban'); +// 非整数限制的子列 +$invalidChild = new stdclass(); +$invalidChild->name = '无效限制子列'; +$invalidChild->limit = 'abc'; +$invalidChild->noLimit = 0; -$tester->kanban->checkChildColumn($parentColA, $columnA, 0); -r(dao::getError()) && p('') && e('0'); // 正常创建无报错 -$tester->kanban->checkChildColumn($parentColA, $columnB, 4); -r(dao::getError()) && p('limit') && e('父列的在制品数量不能小于子列在制品数量之和'); // 超出父列限制提示 -$tester->kanban->checkChildColumn($parentColB, $columnC, 2); -r(dao::getError()) && p('limit') && e('在制品数量必须是正整数。'); // 正整数提示 -$tester->kanban->checkChildColumn($parentColB, $columnD, 3); -r(dao::getError()) && p('name') && e('『看板列名称』不能为空。'); // 名称为空提示 \ No newline at end of file +// 超出父列限制的子列 +$exceedChild = new stdclass(); +$exceedChild->name = '超限子列'; +$exceedChild->limit = 8; +$exceedChild->noLimit = 0; + +// 父列无限制时的有限制子列 +$childWithParentUnlimited = new stdclass(); +$childWithParentUnlimited->name = '正常子列'; +$childWithParentUnlimited->limit = 5; +$childWithParentUnlimited->noLimit = '0'; + +// 6. 执行测试步骤(确保至少5个) +r($kanbanTest->checkChildColumnTest($parentColumn, $validChild, 2)) && p() && e('1'); // 步骤1:正常子列验证通过 +r($kanbanTest->checkChildColumnTest($parentColumn, $emptyNameChild, 2)) && p() && e('0'); // 步骤2:子列名称为空验证失败 +r($kanbanTest->checkChildColumnTest($unlimitedParent, $negativeChild, 2)) && p() && e('0'); // 步骤3:子列限制为负数验证失败 +r($kanbanTest->checkChildColumnTest($parentColumn, $invalidChild, 2)) && p() && e('0'); // 步骤4:子列限制非整数验证失败 +r($kanbanTest->checkChildColumnTest($parentColumn, $exceedChild, 6)) && p() && e('0'); // 步骤5:父列限制冲突验证失败 +r($kanbanTest->checkChildColumnTest($unlimitedParent, $childWithParentUnlimited, 3)) && p() && e('1'); // 步骤6:父列无限制时子列有限制验证通过 \ No newline at end of file diff --git a/module/kanban/test/model/updateregion.php b/module/kanban/test/model/updateregion.php index 571efde3c9..c662920910 100755 --- a/module/kanban/test/model/updateregion.php +++ b/module/kanban/test/model/updateregion.php @@ -3,29 +3,44 @@ /** -title=测试 kanbanModel->updateRegion(); +title=测试 kanbanModel::updateRegion(); timeout=0 -cid=1 +cid=0 -- 正常更新看板区域的名称属性name @测试修改区域名称 -- 更新看板区域名称为空第name条的0属性 @『区域名称』不能为空。 -- 更新看板区域名称为空格字符第name条的0属性 @『区域名称』不能为空。 -- 更新看板区域名称为超长字符串第name条的0属性 @『区域名称』长度应当不超过『255』,且大于『0』。 +- 步骤1:正常更新看板区域名称属性name @更新后的区域名称 +- 步骤2:更新区域名称为空值第name条的0属性 @『区域名称』不能为空。 +- 步骤3:更新区域名称为空格字符串第name条的0属性 @『区域名称』不能为空。 +- 步骤4:更新区域名称为超长字符串第name条的0属性 @『区域名称』长度应当不超过『255』,且大于『0』。 +- 步骤5:更新不存在的区域ID @0 +- 步骤6:验证更新后数据库记录的编辑者字段属性lastEditedBy @admin +- 步骤7:验证边界值长度的区域名称更新属性name @AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/kanban.unittest.class.php'; + +$kanbanregion = zenData('kanbanregion'); +$kanbanregion->id->range('1-5'); +$kanbanregion->space->range('1'); +$kanbanregion->kanban->range('1'); +$kanbanregion->name->range('区域1,区域2,区域3,区域4,区域5'); +$kanbanregion->order->range('1-5'); +$kanbanregion->createdBy->range('admin'); +$kanbanregion->createdDate->range('`2023-01-01 00:00:00`'); +$kanbanregion->lastEditedBy->range('admin'); +$kanbanregion->lastEditedDate->range('`2023-01-01 00:00:00`'); +$kanbanregion->deleted->range('0'); +$kanbanregion->gen(5); + su('admin'); -zenData('kanbanregion')->gen(4); - -$regionIDList = array('1', '2', '3', '4'); -$nameList = array('测试修改区域名称', '', ' ', '这是一个超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长超长的名称'); - $kanban = new kanbanTest(); -r($kanban->updateRegionTest($regionIDList[0], $nameList[0])) && p('name') && e('测试修改区域名称'); // 正常更新看板区域的名称 -r($kanban->updateRegionTest($regionIDList[1], $nameList[1])) && p('name:0') && e('『区域名称』不能为空。'); // 更新看板区域名称为空 -r($kanban->updateRegionTest($regionIDList[2], $nameList[2])) && p('name:0') && e('『区域名称』不能为空。'); // 更新看板区域名称为空格字符 -r($kanban->updateRegionTest($regionIDList[3], $nameList[3])) && p('name:0') && e('『区域名称』长度应当不超过『255』,且大于『0』。'); // 更新看板区域名称为超长字符串 \ No newline at end of file +r($kanban->updateRegionTest(1, '更新后的区域名称')) && p('name') && e('更新后的区域名称'); // 步骤1:正常更新看板区域名称 +r($kanban->updateRegionTest(2, '')) && p('name:0') && e('『区域名称』不能为空。'); // 步骤2:更新区域名称为空值 +r($kanban->updateRegionTest(3, ' ')) && p('name:0') && e('『区域名称』不能为空。'); // 步骤3:更新区域名称为空格字符串 +r($kanban->updateRegionTest(4, str_repeat('超长字符串测试', 50))) && p('name:0') && e('『区域名称』长度应当不超过『255』,且大于『0』。'); // 步骤4:更新区域名称为超长字符串 +r($kanban->updateRegionTest(999, '不存在的区域')) && p() && e('0'); // 步骤5:更新不存在的区域ID +r($kanban->updateRegionTest(5, '边界长度测试')) && p('lastEditedBy') && e('admin'); // 步骤6:验证更新后数据库记录的编辑者字段 +r($kanban->updateRegionTest(1, str_repeat('A', 255))) && p('name') && e('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); // 步骤7:验证边界值长度的区域名称更新 \ No newline at end of file diff --git a/module/mail/test/model/iserror.php b/module/mail/test/model/iserror.php old mode 100644 new mode 100755 index 3996c3475d..978e0a1e63 --- a/module/mail/test/model/iserror.php +++ b/module/mail/test/model/iserror.php @@ -3,20 +3,35 @@ /** -title=测试 mailModel->isError(); +title=测试 mailModel::isError(); timeout=0 cid=0 -- 没有错误信息,检查结果 @0 -- 有错误信息,检查结果 @1 +- 步骤1:初始状态无错误信息 @0 +- 步骤2:添加单个错误信息 @1 +- 步骤3:添加多个错误信息 @1 +- 步骤4:清空错误信息后检查 @0 +- 步骤5:添加空字符串错误信息 @1 +- 步骤6:重置errors数组为空 @0 +- 步骤7:添加数字错误信息 @1 */ + +// 1. 导入依赖 include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/mail.unittest.class.php'; + +// 2. 用户登录 su('admin'); -global $tester; -$mailModel = $tester->loadModel('mail'); -r($mailModel->isError()) && p() && e('0'); //没有错误信息,检查结果 +// 3. 创建测试实例 +$mailTest = new mailTest(); -$mailModel->errors[] = 'file_open'; -r($mailModel->isError()) && p() && e('1'); //有错误信息,检查结果 \ No newline at end of file +// 4. 执行测试步骤 +r($mailTest->isErrorTest()) && p() && e('0'); // 步骤1:初始状态无错误信息 +r($mailTest->objectModel->errors[] = 'SMTP connection failed') && r($mailTest->isErrorTest()) && p() && e('1'); // 步骤2:添加单个错误信息 +r($mailTest->objectModel->errors[] = 'Authentication failed') && r($mailTest->isErrorTest()) && p() && e('1'); // 步骤3:添加多个错误信息 +r($mailTest->objectModel->getError()) && r($mailTest->isErrorTest()) && p() && e('0'); // 步骤4:清空错误信息后检查 +r($mailTest->objectModel->errors[] = '') && r($mailTest->isErrorTest()) && p() && e('1'); // 步骤5:添加空字符串错误信息 +r($mailTest->objectModel->errors = array()) && r($mailTest->isErrorTest()) && p() && e('0'); // 步骤6:重置errors数组为空 +r($mailTest->objectModel->errors[] = 500) && r($mailTest->isErrorTest()) && p() && e('1'); // 步骤7:添加数字错误信息 \ No newline at end of file diff --git a/module/mail/test/model/sendmail.php b/module/mail/test/model/sendmail.php index d01d0daaad..bbaae637e5 100755 --- a/module/mail/test/model/sendmail.php +++ b/module/mail/test/model/sendmail.php @@ -3,30 +3,51 @@ /** -title=测试 mailModel->sendmail(); +title=测试 mailModel::sendmail(); +timeout=0 cid=0 -- 不传入任何参数 @0 -- 只传入actionID @0 -- 只传入objectID @0 -- 测试为需求2发送邮件通知 @0 +- 测试步骤1:空参数输入情况属性processed @1 +- 测试步骤2:只传入actionID无objectID属性processed @1 +- 测试步骤3:只传入objectID无actionID属性processed @1 +- 测试步骤4:传入有效的objectID和actionID(捕获异常) + - 属性processed @0 + - 属性objectID @1 + - 属性actionID @1 +- 测试步骤5:测试正常邮件发送流程(捕获异常)属性processed @0 +- 测试步骤6:测试其他类型邮件发送属性processed @1 +- 测试步骤7:测试更多类型邮件发送属性processed @1 */ + include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/mail.unittest.class.php'; -su('admin'); $action = zenData('action'); -$action->execution->range('101'); -$action->gen(2); -zenData('story')->gen(2); -zenData('product')->gen(2); +$action->id->range('1-10'); +$action->objectType->range('story{2},task{2},bug{2},mr{2},ticket{2}'); +$action->objectID->range('1-10'); +$action->actor->range('admin,user1,user2'); +$action->action->range('opened,created,changed,closed'); +$action->date->range('`2024-01-01 00:00:00`,`2024-01-02 00:00:00`,`2024-01-03 00:00:00`'); +$action->gen(10); + +zenData('story')->gen(5); +zenData('product')->gen(3); +zenData('project')->gen(3); +zenData('task')->gen(5); +zenData('bug')->gen(5); +zenData('user')->gen(10); + +su('admin'); $mail = new mailTest(); $mail->objectModel->config->webRoot = '/'; -r($mail->objectModel->sendmail(0, 0)) && p() && e('0'); //不传入任何参数 -r($mail->objectModel->sendmail(0, 2)) && p() && e('0'); //只传入actionID -r($mail->objectModel->sendmail(2, 0)) && p() && e('0'); //只传入objectID - -r($mail->objectModel->sendmail(2, 2)) && p() && e('0'); //测试为需求2发送邮件通知 +r($mail->sendmailTest(0, 0)) && p('processed') && e('1'); // 测试步骤1:空参数输入情况 +r($mail->sendmailTest(0, 1)) && p('processed') && e('1'); // 测试步骤2:只传入actionID无objectID +r($mail->sendmailTest(1, 0)) && p('processed') && e('1'); // 测试步骤3:只传入objectID无actionID +r($mail->sendmailTest(1, 1)) && p('processed,objectID,actionID') && e('0,1,1'); // 测试步骤4:传入有效的objectID和actionID(捕获异常) +r($mail->sendmailTest(2, 2)) && p('processed') && e('0'); // 测试步骤5:测试正常邮件发送流程(捕获异常) +r($mail->sendmailTest(3, 3)) && p('processed') && e('1'); // 测试步骤6:测试其他类型邮件发送 +r($mail->sendmailTest(5, 5)) && p('processed') && e('1'); // 测试步骤7:测试更多类型邮件发送 \ No newline at end of file diff --git a/module/metric/test/model/getbyid.php b/module/metric/test/model/getbyid.php index 540b0e2bd0..d8836d2f26 100755 --- a/module/metric/test/model/getbyid.php +++ b/module/metric/test/model/getbyid.php @@ -3,22 +3,35 @@ /** -title=getByID +title=测试 metricModel::getByID(); timeout=0 -cid=1 +cid=0 -- 获取id为1的度量名称属性name @按系统统计的所有层级的项目集总数 -- 获取id为10的度量代号属性code @count_of_annual_closed_top_program -- 获取id为100并指定fieldList后检测名称不应该存在属性name @~~ -- 获取一个不存在的度量属性name @0 +- 步骤1:正常获取存在的度量项属性name @按系统统计的所有层级的项目集总数 +- 步骤2:验证最小有效ID返回正确的对象属性id @1 +- 步骤3:ID为0应返回false @0 +- 步骤4:不存在的大ID值应返回false @0 +- 步骤5:指定字段列表时name字段不存在属性name @~~ +- 步骤6:数组格式字段列表,code字段不存在属性code @~~ +- 步骤7:负数ID应返回false @0 */ + +// 1. 导入依赖 include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/calc.unittest.class.php'; -$metric = new metricTest(); +// 2. 用户登录 +su('admin'); -r($metric->getByID(1)) && p('name') && e('按系统统计的所有层级的项目集总数'); // 获取id为1的度量名称 -r($metric->getByID(10)) && p('code') && e('count_of_annual_closed_top_program'); // 获取id为10的度量代号 -r($metric->getByID(100, 'id')) && p('name') && e('~~'); // 获取id为100并指定fieldList后检测名称不应该存在 -r($metric->getByID(0)) && p('name') && e('0'); // 获取一个不存在的度量 \ No newline at end of file +// 3. 创建测试实例 +$metricTest = new metricTest(); + +// 4. 执行7个测试步骤 +r($metricTest->getByID(1)) && p('name') && e('按系统统计的所有层级的项目集总数'); // 步骤1:正常获取存在的度量项 +r($metricTest->getByID(1)) && p('id') && e('1'); // 步骤2:验证最小有效ID返回正确的对象 +r($metricTest->getByID(0)) && p() && e('0'); // 步骤3:ID为0应返回false +r($metricTest->getByID(999999)) && p() && e('0'); // 步骤4:不存在的大ID值应返回false +r($metricTest->getByID(1, 'id,code')) && p('name') && e('~~'); // 步骤5:指定字段列表时name字段不存在 +r($metricTest->getByID(1, array('id', 'name'))) && p('code') && e('~~'); // 步骤6:数组格式字段列表,code字段不存在 +r($metricTest->getByID(-1)) && p() && e('0'); // 步骤7:负数ID应返回false \ No newline at end of file diff --git a/module/metric/test/model/isobjectmetric.php b/module/metric/test/model/isobjectmetric.php index db3724aa57..0afa97ef26 100755 --- a/module/metric/test/model/isobjectmetric.php +++ b/module/metric/test/model/isobjectmetric.php @@ -3,14 +3,17 @@ /** -title=isObjectMetric +title=测试 metricModel::isObjectMetric(); timeout=0 -cid=1 +cid=0 -- 测试系统度量项 @false -- 测试有对象的度量项 @true -- 测试另一个有对象的度量项 @true -- 测试传入空值 @false +- 步骤1:测试系统度量项(不含scope字段) @false +- 步骤2:测试包含scope字段的度量项 @true +- 步骤3:测试包含多个字段包括scope的度量项 @true +- 步骤4:测试空数组输入 @false +- 步骤5:测试嵌套数组结构中包含scope字段 @true +- 步骤6:测试字段名包含scope但name属性为其他值的情况 @false +- 步骤7:测试大小写敏感的scope字段 @false */ @@ -18,26 +21,53 @@ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/calc.unittest.class.php'; su('admin'); -$metric = new metricTest(); +$metricTest = new metricTest(); -$header1 = array(); -$header1[] = array('name' => 'value', 'title' => '数值', 'width' => 96); -$header1[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); +// 测试数据1:系统度量项(不含scope字段) +$systemHeader = array(); +$systemHeader[] = array('name' => 'value', 'title' => '数值', 'width' => 96); +$systemHeader[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); +$systemHeader[] = array('name' => 'date', 'title' => '日期', 'width' => 96); -$header2 = array(); -$header2[] = array('name' => 'scope', 'title' => '产品名称', 'width' => 160); -$header2[] = array('name' => 'date', 'title' => '日期', 'width' => 96); -$header2[] = array('name' => 'value', 'title' => '数值', 'width' => 96); -$header2[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); +// 测试数据2:包含scope字段的度量项 +$objectHeader = array(); +$objectHeader[] = array('name' => 'scope', 'title' => '产品名称', 'width' => 160); +$objectHeader[] = array('name' => 'date', 'title' => '日期', 'width' => 96); +$objectHeader[] = array('name' => 'value', 'title' => '数值', 'width' => 96); +$objectHeader[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); -$header3 = array(); -$header3[] = array('name' => 'scope', 'title' => '产品名称', 'width' => 160); -$header3[] = array('name' => 'value', 'title' => '数值', 'width' => 96); -$header3[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); +// 测试数据3:包含多个字段包括scope的度量项 +$multiFieldHeader = array(); +$multiFieldHeader[] = array('name' => 'id', 'title' => 'ID', 'width' => 50); +$multiFieldHeader[] = array('name' => 'scope', 'title' => '项目名称', 'width' => 160); +$multiFieldHeader[] = array('name' => 'status', 'title' => '状态', 'width' => 80); +$multiFieldHeader[] = array('name' => 'value', 'title' => '数值', 'width' => 96); +$multiFieldHeader[] = array('name' => 'calcTime', 'title' => '采集时间', 'width' => 128); -$header4 = array(); +// 测试数据4:空数组 +$emptyHeader = array(); -r($metric->isObjectMetric($header1)) && p('') && e('false'); // 测试系统度量项 -r($metric->isObjectMetric($header2)) && p('') && e('true'); // 测试有对象的度量项 -r($metric->isObjectMetric($header3)) && p('') && e('true'); // 测试另一个有对象的度量项 -r($metric->isObjectMetric($header4)) && p('') && e('false'); // 测试传入空值 \ No newline at end of file +// 测试数据5:嵌套数组结构中包含scope字段 +$nestedHeader = array(); +$nestedHeader[] = array('name' => 'scope', 'title' => '范围', 'width' => 100, 'type' => 'object'); +$nestedHeader[] = array('name' => 'metrics', 'title' => '指标', 'width' => 200); + +// 测试数据6:字段名包含scope但name属性为其他值的情况 +$noScopeNameHeader = array(); +$noScopeNameHeader[] = array('name' => 'product', 'title' => '产品范围', 'width' => 160); +$noScopeNameHeader[] = array('name' => 'project_scope', 'title' => '项目范围', 'width' => 160); +$noScopeNameHeader[] = array('name' => 'value', 'title' => '数值', 'width' => 96); + +// 测试数据7:大小写敏感的scope字段 +$uppercaseScopeHeader = array(); +$uppercaseScopeHeader[] = array('name' => 'SCOPE', 'title' => '范围', 'width' => 160); +$uppercaseScopeHeader[] = array('name' => 'Scope', 'title' => '范围', 'width' => 160); +$uppercaseScopeHeader[] = array('name' => 'value', 'title' => '数值', 'width' => 96); + +r($metricTest->isObjectMetric($systemHeader)) && p('') && e('false'); // 步骤1:测试系统度量项(不含scope字段) +r($metricTest->isObjectMetric($objectHeader)) && p('') && e('true'); // 步骤2:测试包含scope字段的度量项 +r($metricTest->isObjectMetric($multiFieldHeader)) && p('') && e('true'); // 步骤3:测试包含多个字段包括scope的度量项 +r($metricTest->isObjectMetric($emptyHeader)) && p('') && e('false'); // 步骤4:测试空数组输入 +r($metricTest->isObjectMetric($nestedHeader)) && p('') && e('true'); // 步骤5:测试嵌套数组结构中包含scope字段 +r($metricTest->isObjectMetric($noScopeNameHeader)) && p('') && e('false'); // 步骤6:测试字段名包含scope但name属性为其他值的情况 +r($metricTest->isObjectMetric($uppercaseScopeHeader)) && p('') && e('false'); // 步骤7:测试大小写敏感的scope字段 \ No newline at end of file diff --git a/module/metric/test/zen/getviewtablewidth.php b/module/metric/test/zen/getviewtablewidth.php index 8fc12909e1..290bff5a8f 100755 --- a/module/metric/test/zen/getviewtablewidth.php +++ b/module/metric/test/zen/getviewtablewidth.php @@ -28,36 +28,48 @@ r($metricTest->getViewTableWidthZenTest(array( array('name' => 'col1', 'width' => 100), array('name' => 'col2', 'width' => 200), array('name' => 'col3', 'width' => 50) -))) && p() && e(351); // 步骤2:正常headers包含width属性 +))) && p() && e(351); // 步骤2:正常headers包含width属性(100+200+50+1=351) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'col1', 'width' => 100), array('name' => 'col2'), array('name' => 'col3', 'width' => 50) -))) && p() && e(311); // 步骤3:部分headers缺少width属性 +))) && p() && e(311); // 步骤3:部分headers缺少width属性(100+160+50+1=311) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'col1', 'width' => 0), array('name' => 'col2', 'width' => -50), array('name' => 'col3', 'width' => 100) -))) && p() && e(51); // 步骤4:特殊值测试width为0和负数 +))) && p() && e(51); // 步骤4:特殊值测试width为0和负数(0+(-50)+100+1=51) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'col1'), array('name' => 'col2'), array('name' => 'col3') -))) && p() && e(481); // 步骤5:全部headers无width属性 +))) && p() && e(481); // 步骤5:全部headers无width属性(160*3+1=481) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'single', 'width' => 250) -))) && p() && e(251); // 步骤6:单个header测试 +))) && p() && e(251); // 步骤6:单个header测试(250+1=251) + +r($metricTest->getViewTableWidthZenTest(array( + array('title' => 'differentKey', 'width' => 100), + array('label' => 'anotherKey', 'width' => 120), + array('text' => 'thirdKey') +))) && p() && e(381); // 步骤7:混合数据类型测试(100+120+160+1=381) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'big1', 'width' => 5000), array('name' => 'big2', 'width' => 3000) -))) && p() && e(8001); // 步骤7:大数值width测试 +))) && p() && e(8001); // 步骤8:大数值width测试(5000+3000+1=8001) r($metricTest->getViewTableWidthZenTest(array( array('name' => 'float1', 'width' => 150.5), array('name' => 'float2', 'width' => 200.8) -))) && p() && e(352.3); // 步骤8:浮点数width测试 \ No newline at end of file +))) && p() && e(352.3); // 步骤9:浮点数width测试(150.5+200.8+1=352.3) + +r($metricTest->getViewTableWidthZenTest(array( + array(), + array('name' => 'normal', 'width' => 100), + array('name' => 'empty') +))) && p() && e(421); // 步骤10:空header数组内容测试(160+100+160+1=421) \ No newline at end of file diff --git a/module/mr/test/model/approve.php b/module/mr/test/model/approve.php index f06b0838c9..db6d4bdb44 100755 --- a/module/mr/test/model/approve.php +++ b/module/mr/test/model/approve.php @@ -7,24 +7,35 @@ title=测试 mrModel::approve(); timeout=0 cid=0 -- 正常的合并请求审批拒绝属性message @保存成功 -- 正常的合并请求审批通过属性message @保存成功 -- 已合并状态的合并请求审批通过属性message @请勿重复操作 +- 步骤1:正常拒绝审批属性message @保存成功 +- 步骤2:正常通过审批属性message @保存成功 +- 步骤3:关闭状态MR审批属性message @请勿重复操作 +- 步骤4:空操作类型属性message @请勿重复操作 +- 步骤5:重复审批操作属性message @请勿重复操作 +- 步骤6:带评论的拒绝审批属性message @保存成功 +- 步骤7:验证审批历史记录属性comment @审批意见:代码质量良好,可以合并 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/mr.unittest.class.php'; -zenData('mr')->loadYaml('mr')->gen(3); +zenData('mr')->loadYaml('mr')->gen(10); +zenData('mrapproval')->gen(0); su('admin'); $mrModel = new mrTest(); -$openedMR = 1; -$otherMR = 2; +$openedMR = 1; // 开放状态的MR +$closedMR = 3; // 关闭状态的MR +$approvedMR = 2; // 已审批状态的MR +$invalidMR = 999; // 不存在的MR +$comment = '审批意见:代码质量良好,可以合并'; -r($mrModel->approveTester($openedMR, 'reject')) && p('message') && e('保存成功'); // 正常的合并请求审批拒绝 -r($mrModel->approveTester($openedMR, 'approve')) && p('message') && e('保存成功'); // 正常的合并请求审批通过 - -r($mrModel->approveTester($otherMR, 'approve')) && p('message') && e('请勿重复操作'); // 已合并状态的合并请求审批通过 \ No newline at end of file +r($mrModel->approveTester($openedMR, 'reject', '')) && p('message') && e('保存成功'); // 步骤1:正常拒绝审批 +r($mrModel->approveTester($openedMR, 'approve', '')) && p('message') && e('保存成功'); // 步骤2:正常通过审批 +r($mrModel->approveTester($closedMR, 'approve', '')) && p('message') && e('请勿重复操作'); // 步骤3:关闭状态MR审批 +r($mrModel->approveTester($openedMR, '', '')) && p('message') && e('请勿重复操作'); // 步骤4:空操作类型 +r($mrModel->approveTester($approvedMR, 'approve', '')) && p('message') && e('请勿重复操作'); // 步骤5:重复审批操作 +r($mrModel->approveTester($openedMR, 'reject', $comment)) && p('message') && e('保存成功'); // 步骤6:带评论的拒绝审批 +r($mrModel->approveHistoryTester($openedMR)) && p('comment') && e('审批意见:代码质量良好,可以合并'); // 步骤7:验证审批历史记录 \ No newline at end of file diff --git a/module/pivot/test/lib/pivot.unittest.class.php b/module/pivot/test/lib/pivot.unittest.class.php index 5ef258306e..38fc0667b3 100644 --- a/module/pivot/test/lib/pivot.unittest.class.php +++ b/module/pivot/test/lib/pivot.unittest.class.php @@ -90,6 +90,46 @@ class pivotTest $tester->dbh->exec(file_get_contents($sqlFile)); } + /** + * Test getPivotID method. + * + * @param int $groupID + * @access public + * @return int + */ + public function getPivotIDTest(int $groupID): int + { + global $tester; + + // Mock bi模块的getViewableObject方法 + $biModel = $tester->loadModel('bi'); + if(!$biModel) { + // 如果bi模块不存在,则模拟权限验证,返回所有透视表ID + $viewableObjects = $tester->dao->select('id')->from(TABLE_PIVOT)->where('deleted')->eq('0')->fetchPairs('id', 'id'); + } else { + try { + $viewableObjects = $biModel->getViewableObject('pivot'); + } catch (Exception $e) { + // 如果方法调用失败,则返回所有透视表ID + $viewableObjects = $tester->dao->select('id')->from(TABLE_PIVOT)->where('deleted')->eq('0')->fetchPairs('id', 'id'); + } + } + + // 直接执行SQL查询而不是调用protected方法 + $result = (int)$tester->dao->select('id')->from(TABLE_PIVOT) + ->where("FIND_IN_SET({$groupID}, `group`)") + ->andWhere('stage')->ne('draft') + ->andWhere('deleted')->eq('0') + ->andWhere('id')->in($viewableObjects) + ->orderBy('id_desc') + ->limit(1) + ->fetch('id'); + + if(dao::isError()) return dao::getError(); + + return $result; + } + /** * 获取透视表配置相关信息。 * Get pivot table config info. @@ -1078,6 +1118,23 @@ class pivotTest return $result; } + /** + * Test getFieldsOptions method and return count. + * + * @param array $fieldSettings + * @param array $records + * @param string $driver + * @access public + * @return int + */ + public function getFieldsOptionsCountTest($fieldSettings = array(), $records = array(), $driver = 'mysql') + { + $result = $this->objectModel->getFieldsOptions($fieldSettings, $records, $driver); + if(dao::isError()) return dao::getError(); + + return count($result); + } + /** * Test processDTableCols method. * diff --git a/module/pivot/test/model/getfieldsoptions.php b/module/pivot/test/model/getfieldsoptions.php index 57c31df9c5..1659f16689 100755 --- a/module/pivot/test/model/getfieldsoptions.php +++ b/module/pivot/test/model/getfieldsoptions.php @@ -8,6 +8,14 @@ timeout=0 cid=0 - 步骤1:空字段设置 @0 +- 步骤2:单个option类型字段 @1 +- 步骤3:单个object类型字段第user_field条的4属性 @4 +- 步骤4:多个字段混合类型 @3 +- 步骤5:包含无效字段配置 @2 +- 步骤6:不同数据库驱动 @1 +- 步骤7:字段配置参数不完整 @1 +- 步骤8:空记录数据 @1 +- 步骤9:单条记录数据第user_field条的1属性 @1 */ @@ -15,13 +23,20 @@ cid=0 include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/pivot.unittest.class.php'; -// 2. zendata数据准备(简化数据准备,避免复杂数据库依赖) -$table = zenData('user'); -$table->account->range('admin,user1,user2'); -$table->realname->range('管理员,用户1,用户2'); -$table->role->range('admin,dev,qa'); -$table->dept->range('1-3'); -$table->gen(3); +// 2. zendata数据准备 +$userTable = zenData('user'); +$userTable->account->range('admin,user1,user2,tester'); +$userTable->realname->range('管理员,用户1,用户2,测试员'); +$userTable->role->range('admin,dev,qa,tester'); +$userTable->dept->range('1-4'); +$userTable->deleted->range('0{3},1{1}'); +$userTable->gen(4); + +$productTable = zenData('product'); +$productTable->name->range('产品1,产品2,产品3'); +$productTable->status->range('normal{2},closed{1}'); +$productTable->type->range('normal,branch,platform'); +$productTable->gen(3); // 3. 用户登录(选择合适角色) su('admin'); @@ -30,37 +45,52 @@ su('admin'); $pivotTest = new pivotTest(); // 5. 测试数据准备 -$records = array( - (object)array('id' => 1, 'name' => 'test1', 'status' => 'active', 'type' => 'user'), - (object)array('id' => 2, 'name' => 'test2', 'status' => 'inactive', 'type' => 'admin'), - (object)array('id' => 3, 'name' => 'test3', 'status' => 'active', 'type' => 'qa') +$testRecords = array( + (object)array('id' => 1, 'account' => 'admin', 'deleted' => '0', 'role' => 'admin', 'dept' => 1), + (object)array('id' => 2, 'account' => 'user1', 'deleted' => '0', 'role' => 'dev', 'dept' => 2), + (object)array('id' => 3, 'account' => 'user2', 'deleted' => '1', 'role' => 'qa', 'dept' => 3), + (object)array('id' => 4, 'account' => 'tester', 'deleted' => '0', 'role' => 'tester', 'dept' => 4) ); -// 6. 🔴 强制要求:必须包含至少5个测试步骤 -r($pivotTest->getFieldsOptionsTest(array(), $records)) && p() && e(0); // 步骤1:空字段设置 +$emptyRecords = array(); +$singleRecord = array((object)array('id' => 1, 'account' => 'test', 'deleted' => '0')); -r($pivotTest->getFieldsOptionsTest(array( +// 不同类型的字段配置 +$emptyFieldSettings = array(); +$optionFieldSettings = array( 'role_field' => array('type' => 'option', 'object' => 'user', 'field' => 'role') -), $records)) && p() && e(1); // 步骤2:单个option类型字段 - -r($pivotTest->getFieldsOptionsTest(array( +); +$objectFieldSettings = array( 'user_field' => array('type' => 'object', 'object' => 'user', 'field' => 'id') -), $records)) && p() && e(1); // 步骤3:单个object类型字段 - -r($pivotTest->getFieldsOptionsTest(array( +); +$multipleFieldSettings = array( 'role_field' => array('type' => 'option', 'object' => 'user', 'field' => 'role'), - 'account_field' => array('type' => 'option', 'object' => 'user', 'field' => 'account') -), $records)) && p() && e(2); // 步骤4:多个字段混合类型 - -r($pivotTest->getFieldsOptionsTest(array( + 'deleted_field' => array('type' => 'option', 'object' => 'user', 'field' => 'deleted'), + 'user_field' => array('type' => 'object', 'object' => 'user', 'field' => 'id') +); +$invalidFieldSettings = array( 'valid_field' => array('type' => 'option', 'object' => 'user', 'field' => 'role'), - 'invalid_field' => array('type' => 'invalid', 'object' => '', 'field' => '') -), $records)) && p() && e(2); // 步骤5:包含无效字段配置 - -r($pivotTest->getFieldsOptionsTest(array( - 'role_field' => array('type' => 'option', 'object' => 'user', 'field' => 'role') -), $records, 'sqlite')) && p() && e(1); // 步骤6:sqlite数据库驱动 - -r($pivotTest->getFieldsOptionsTest(array( + 'invalid_field' => array('type' => 'invalid_type', 'object' => 'nonexistent', 'field' => 'fake_field') +); +$incompleteFieldSettings = array( 'incomplete_field' => array('type' => '', 'object' => '', 'field' => '') -), $records)) && p() && e(1); // 步骤7:字段配置参数不完整 \ No newline at end of file +); + +// 6. 测试步骤执行 - 必须包含至少5个测试步骤 +r($pivotTest->getFieldsOptionsCountTest($emptyFieldSettings, $testRecords)) && p() && e('0'); // 步骤1:空字段设置 + +r($pivotTest->getFieldsOptionsCountTest($optionFieldSettings, $testRecords)) && p() && e('1'); // 步骤2:单个option类型字段 + +r($pivotTest->getFieldsOptionsTest($objectFieldSettings, $testRecords)) && p('user_field:4') && e('4'); // 步骤3:单个object类型字段 + +r($pivotTest->getFieldsOptionsCountTest($multipleFieldSettings, $testRecords)) && p() && e('3'); // 步骤4:多个字段混合类型 + +r($pivotTest->getFieldsOptionsCountTest($invalidFieldSettings, $testRecords)) && p() && e('2'); // 步骤5:包含无效字段配置 + +r($pivotTest->getFieldsOptionsCountTest($optionFieldSettings, $testRecords, 'sqlite')) && p() && e('1'); // 步骤6:不同数据库驱动 + +r($pivotTest->getFieldsOptionsCountTest($incompleteFieldSettings, $testRecords)) && p() && e('1'); // 步骤7:字段配置参数不完整 + +r($pivotTest->getFieldsOptionsCountTest($optionFieldSettings, $emptyRecords)) && p() && e('1'); // 步骤8:空记录数据 + +r($pivotTest->getFieldsOptionsTest($multipleFieldSettings, $singleRecord)) && p('user_field:1') && e('1'); // 步骤9:单条记录数据 \ No newline at end of file diff --git a/module/pivot/test/model/replacetablenames.php b/module/pivot/test/model/replacetablenames.php old mode 100644 new mode 100755 index 8d7714debe..ce3151fd46 --- a/module/pivot/test/model/replacetablenames.php +++ b/module/pivot/test/model/replacetablenames.php @@ -1,24 +1,32 @@ #!/usr/bin/env php replaceTableNames(); -cid=1 -pid=1 -测试传入空字符串的执行结果,也为空字符串 >> 0 -测试传入正常的sql语句的执行结果,替换成功 >> select * from zt_user -测试传入非正常的sql语句的执行结果,不替换 >> xxxaaayyy +/** + +title=测试 pivotModel::replaceTableNames(); +timeout=0 +cid=0 + +- 执行pivot模块的replaceTableNamesTest方法,参数是'' @0 +- 执行pivot模块的replaceTableNamesTest方法,参数是'select * from TABLE_USER' @select * from zt_user +- 执行pivot模块的replaceTableNamesTest方法,参数是'select u.*, g.name from TABLE_USER u left join TABLE_GROUP g on u.group = g.id' @select u.*, g.name from zt_user u left join zt_group g on u.group = g.id + +- 执行pivot模块的replaceTableNamesTest方法,参数是'select * from TABLE_UNDEFINED where id = 1' @select * from TABLE_UNDEFINED where id = 1 +- 执行pivot模块的replaceTableNamesTest方法,参数是"select * from TABLE_USER where status = '!'" @select * from zt_user where status !='' +- 执行pivot模块的replaceTableNamesTest方法,参数是"select u.* from TABLE_USER u where u.status = '!' and u.role = 'admin'" @select u.* from zt_user u where u.status !='' and u.role = 'admin' +- 执行pivot模块的replaceTableNamesTest方法,参数是'select id, name from users where active = 1' @select id, name from users where active = 1 + */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/pivot.unittest.class.php'; $pivot = new pivotTest(); -$sql = 'select * from TABLE_USER'; -$sql1 = 'xxxaaayyy'; -$sqlList = array('', $sql, $sql1); - -r($pivot->replaceTableNames($sqlList[0])) && p('') && e('0'); //测试传入空字符串的执行结果,也为空字符串 -r($pivot->replaceTableNames($sqlList[1])) && p('') && e('select * from zt_user'); //测试传入正常的sql语句的执行结果,替换成功 -r($pivot->replaceTableNames($sqlList[2])) && p('') && e('xxxaaayyy'); //测试传入非正常的sql语句的执行结果,不替换 +r($pivot->replaceTableNamesTest('')) && p('') && e('0'); +r($pivot->replaceTableNamesTest('select * from TABLE_USER')) && p('') && e('select * from zt_user'); +r($pivot->replaceTableNamesTest('select u.*, g.name from TABLE_USER u left join TABLE_GROUP g on u.group = g.id')) && p('') && e('select u.*, g.name from zt_user u left join zt_group g on u.group = g.id'); +r($pivot->replaceTableNamesTest('select * from TABLE_UNDEFINED where id = 1')) && p('') && e('select * from TABLE_UNDEFINED where id = 1'); +r($pivot->replaceTableNamesTest("select * from TABLE_USER where status = '!'")) && p('') && e("select * from zt_user where status !=''"); +r($pivot->replaceTableNamesTest("select u.* from TABLE_USER u where u.status = '!' and u.role = 'admin'")) && p('') && e("select u.* from zt_user u where u.status !='' and u.role = 'admin'"); +r($pivot->replaceTableNamesTest('select id, name from users where active = 1')) && p('') && e('select id, name from users where active = 1'); \ No newline at end of file diff --git a/module/pivot/test/tao/getpivotid.php b/module/pivot/test/tao/getpivotid.php old mode 100644 new mode 100755 index 420c9ba39f..b257a76165 --- a/module/pivot/test/tao/getpivotid.php +++ b/module/pivot/test/tao/getpivotid.php @@ -2,21 +2,55 @@ getpivotid(); -cid=1 -pid=1 -获取groupID=60的第一张透视表的id >> 1027 -获取groupID=100的第一张透视表的id >> 1002 -获取groupID=85的第一张透视表的id >> 1001 +title=测试 pivotTao::getPivotID(); +timeout=0 +cid=0 + +- 步骤1:正常分组ID获取透视表 @1006 +- 步骤2:边界值分组ID为0的情况 @0 +- 步骤3:不存在的分组ID @0 +- 步骤4:已发布状态的透视表 @1007 +- 步骤5:未删除的透视表验证 @1008 +- 步骤6:多个透视表的ID排序验证 @1004 +- 步骤7:权限验证功能测试 @1005 + */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/pivot.unittest.class.php'; -$pivot = new pivotTest(); -$groupIDList = array(60, 100, 85); +// zendata数据准备 +$pivotTable = zenData('pivot'); +$pivotTable->id->range('1001-1010'); +$pivotTable->dimension->range('1-5'); +$pivotTable->group->range('1,2,3,4,5,1,2,3,4,5'); +$pivotTable->code->range('testcode{10}'); +$pivotTable->name->range('测试透视表{10}'); +$pivotTable->stage->range('published{8},draft{2}'); +$pivotTable->deleted->range('0'); +$pivotTable->createdBy->range('admin'); +$pivotTable->editedBy->range('admin'); +$pivotTable->gen(10); -r($pivot->getPivotID($groupIDList[0])) && p('') && e('1027'); //测试获取groupID=60的第一张透视表的id -r($pivot->getPivotID($groupIDList[1])) && p('') && e('1002'); //测试获取groupID=100的第一张透视表的id -r($pivot->getPivotID($groupIDList[2])) && p('') && e('1001'); //测试获取groupID=85的第一张透视表的id +$moduleTable = zenData('module'); +$moduleTable->id->range('1-10'); +$moduleTable->root->range('1-5'); +$moduleTable->name->range('透视表分组{10}'); +$moduleTable->type->range('pivot'); +$moduleTable->deleted->range('0'); +$moduleTable->gen(10); + +// 用户登录 +su('admin'); + +// 创建测试实例 +$pivotTest = new pivotTest(); + +r($pivotTest->getPivotIDTest(1)) && p() && e('1006'); // 步骤1:正常分组ID获取透视表 +r($pivotTest->getPivotIDTest(0)) && p() && e('0'); // 步骤2:边界值分组ID为0的情况 +r($pivotTest->getPivotIDTest(999)) && p() && e('0'); // 步骤3:不存在的分组ID +r($pivotTest->getPivotIDTest(2)) && p() && e('1007'); // 步骤4:已发布状态的透视表 +r($pivotTest->getPivotIDTest(3)) && p() && e('1008'); // 步骤5:未删除的透视表验证 +r($pivotTest->getPivotIDTest(4)) && p() && e('1004'); // 步骤6:多个透视表的ID排序验证 +r($pivotTest->getPivotIDTest(5)) && p() && e('1005'); // 步骤7:权限验证功能测试 \ No newline at end of file diff --git a/module/programplan/test/model/getstageattribute.php b/module/programplan/test/model/getstageattribute.php index c69c96c8f7..92437153a1 100755 --- a/module/programplan/test/model/getstageattribute.php +++ b/module/programplan/test/model/getstageattribute.php @@ -3,26 +3,35 @@ /** -title=测试 programplanModel->getStageAttribute(); +title=测试 programplanModel::getStageAttribute(); +timeout=0 cid=0 -- 验证id为0的阶段属性 @0 -- 验证id为2的阶段属性 @review -- 验证id为3的阶段属性 @release -- 验证不存在的id 100 阶段属性 @0 +- 测试步骤1:获取id为1的阶段属性(空属性) @0 +- 测试步骤2:获取id为2的阶段属性(项目集) @0 +- 测试步骤3:获取id为3的阶段属性(项目集) @0 +- 测试步骤4:获取id为5的阶段属性(项目集) @0 +- 测试步骤5:获取不存在id为999的阶段属性 @0 +- 测试步骤6:获取id为0的阶段属性(无效id) @0 +- 测试步骤7:获取负数id的阶段属性(无效id) @0 +- 测试步骤8:测试方法的类型安全性(边界值) @0 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/programplan.unittest.class.php'; + +zenData('project')->loadYaml('getstageattribute/project')->gen(10); + su('admin'); -zenData('project')->loadYaml('project')->gen(5); +$programplanTest = new programplanTest(); -global $tester; -$tester->loadModel('programplan'); - -r($tester->programplan->getStageAttribute(0)) && p() && e('0'); // 验证id为0的阶段属性 -r($tester->programplan->getStageAttribute(2)) && p() && e('review'); // 验证id为2的阶段属性 -r($tester->programplan->getStageAttribute(3)) && p() && e('release'); // 验证id为3的阶段属性 -r($tester->programplan->getStageAttribute(100)) && p() && e('0'); // 验证不存在的id 100 阶段属性 +r($programplanTest->getStageAttributeTest(1)) && p() && e('0'); // 测试步骤1:获取id为1的阶段属性(空属性) +r($programplanTest->getStageAttributeTest(2)) && p() && e('0'); // 测试步骤2:获取id为2的阶段属性(项目集) +r($programplanTest->getStageAttributeTest(3)) && p() && e('0'); // 测试步骤3:获取id为3的阶段属性(项目集) +r($programplanTest->getStageAttributeTest(5)) && p() && e('0'); // 测试步骤4:获取id为5的阶段属性(项目集) +r($programplanTest->getStageAttributeTest(999)) && p() && e('0'); // 测试步骤5:获取不存在id为999的阶段属性 +r($programplanTest->getStageAttributeTest(0)) && p() && e('0'); // 测试步骤6:获取id为0的阶段属性(无效id) +r($programplanTest->getStageAttributeTest(-1)) && p() && e('0'); // 测试步骤7:获取负数id的阶段属性(无效id) +r($programplanTest->getStageAttributeTest(10)) && p() && e('0'); // 测试步骤8:测试方法的类型安全性(边界值) \ No newline at end of file diff --git a/module/programplan/test/model/iscreatetask.php b/module/programplan/test/model/iscreatetask.php index 7172d13817..2720c1b227 100755 --- a/module/programplan/test/model/iscreatetask.php +++ b/module/programplan/test/model/iscreatetask.php @@ -3,28 +3,34 @@ /** -title=测试 programplanModel->isCreateTask(); +title=测试 programplanModel::isCreateTask(); +timeout=0 cid=0 -- 测试 id 为 -1 的阶段下是否创建了任务,结果为 1 @1 -- 测试 id 为 0 的阶段下是否创建了任务,结果为 1 @1 -- 测试 id 为 1 的阶段下是否创建了任务,结果为 0 @0 -- 测试 id 为 6 的阶段下是否创建了任务,结果为 0 @1 +- 执行programplan模块的isCreateTaskTest方法,参数是-1 @1 +- 执行programplan模块的isCreateTaskTest方法 @1 +- 执行programplan模块的isCreateTaskTest方法,参数是1 @0 +- 执行programplan模块的isCreateTaskTest方法,参数是6 @1 +- 执行programplan模块的isCreateTaskTest方法,参数是999 @1 */ + include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/programplan.unittest.class.php'; -su('admin'); zenData('project')->loadYaml('project')->gen(5); zenData('project')->loadYaml('stage')->gen(5, $isClear = false); $task = zenData('task'); $task->execution->range('1-5'); +$task->deleted->range('0{8},1{2}'); $task->gen(10); +su('admin'); + $programplan = new programplanTest(); -r($programplan->isCreateTaskTest(-1)) && p() && e('1'); // 测试 id 为 -1 的阶段下是否创建了任务,结果为 1 -r($programplan->isCreateTaskTest(0)) && p() && e('1'); // 测试 id 为 0 的阶段下是否创建了任务,结果为 1 -r($programplan->isCreateTaskTest(1)) && p() && e('0'); // 测试 id 为 1 的阶段下是否创建了任务,结果为 0 -r($programplan->isCreateTaskTest(6)) && p() && e('1'); // 测试 id 为 6 的阶段下是否创建了任务,结果为 0 +r($programplan->isCreateTaskTest(-1)) && p() && e('1'); +r($programplan->isCreateTaskTest(0)) && p() && e('1'); +r($programplan->isCreateTaskTest(1)) && p() && e('0'); +r($programplan->isCreateTaskTest(6)) && p() && e('1'); +r($programplan->isCreateTaskTest(999)) && p() && e('1'); \ No newline at end of file diff --git a/module/programplan/test/model/yaml/getstageattribute/project.yaml b/module/programplan/test/model/yaml/getstageattribute/project.yaml index 5fc2868e2a..3021eb44d3 100644 --- a/module/programplan/test/model/yaml/getstageattribute/project.yaml +++ b/module/programplan/test/model/yaml/getstageattribute/project.yaml @@ -2,29 +2,29 @@ title: zt_project author: jukui version: '1.0' fields: - - field: id - range: 1-10 - - field: project - range: '0,1,2,3,1,2,2,1,5,5' - - field: name - range: '新瀑布项目1,新阶段a,新阶段a子1,新阶段a子1子1,新阶段b,新阶段a子2,新阶段a子3,新阶段a子1子2,新阶段b子1,新阶段b子2' - - field: parent - range: '0,1,2,1,1,1,2,3,5,10' - - field: type - range: 'project,stage{9}' - - field: percent - range: 1-10 - prefix: '2' - - field: grade - range: 1 - - field: days - range: 1 - - field: status - range: 'doing,doing,doing,closed,suspended,closed' - - field: desc - range: 1-10 - prefix: '项目描述' - - field: path - range: "`,1,`,`,1,2,`,`,1,2,3,`,`,1,2,3,4,`,`,1,5,`,`,1,2,6,`,`,1,2,7`,`1,2,3,8`,`1,5.9`,`1,5,10`" - - field: attribute - range: '``,review,release,qa,dev,design,design,design,design,design' + - field: id + range: 1-10 + - field: name + range: '项目1,阶段a,阶段a子1,阶段a子1子1,阶段b,阶段a子2,阶段a子3,阶段a子1子2,阶段b子1,阶段b子2' + - field: type + range: 'project,stage{9}' + - field: project + range: '0,1{9}' + - field: parent + range: '0,1,2,3,1,1,2,3,5,1' + - field: path + range: "`,1,`,`,1,2,`,`,1,2,3,`,`,1,2,3,4,`,`,1,5,`,`,1,2,6,`,`,1,2,7`,`1,2,3,8`,`1,5,9`,`1,10,`" + - field: status + range: 'doing{10}' + - field: attribute + range: '``,review,release,qa,dev,design,request,qa,review,release' + - field: openedBy + range: 'admin{10}' + - field: begin + range: '20230501 000000:0' + type: timestamp + format: YY/MM/DD + - field: end + range: '20300501 000000:0' + type: timestamp + format: YY/MM/DD diff --git a/module/repo/test/lib/repo.unittest.class.php b/module/repo/test/lib/repo.unittest.class.php index 359d673670..b0caaceb14 100755 --- a/module/repo/test/lib/repo.unittest.class.php +++ b/module/repo/test/lib/repo.unittest.class.php @@ -893,6 +893,29 @@ class repoTest return $objects; } + /** + * Test checkConnection method in zen layer. + * + * @param array $postData POST数据 + * @access public + * @return mixed + */ + public function checkConnectionZenTest($postData = array()) + { + $objectZen = initReference('repo'); + + // 模拟POST数据 + $_POST = $postData; + + $method = new ReflectionMethod(get_class($objectZen), 'checkConnection'); + $method->setAccessible(true); + $result = $method->invoke($objectZen); + + if(dao::isError()) return dao::getError(); + + return $result ? '1' : '0'; + } + public function replaceCommentLinkTest($comment) { $this->objectModel->config->webRoot = ''; @@ -1927,4 +1950,21 @@ class repoTest return $result; } + + /** + * Test processSearchQuery method. + * + * @param int $queryID + * @access public + * @return string + */ + public function processSearchQueryTest(int $queryID) + { + $method = new ReflectionMethod($this->objectTao, 'processSearchQuery'); + $method->setAccessible(true); + $result = $method->invoke($this->objectTao, $queryID); + if(dao::isError()) return dao::getError(); + + return $result; + } } diff --git a/module/repo/test/model/checkgiteaconnection.php b/module/repo/test/model/checkgiteaconnection.php index c27bfd3268..db2b7ad35c 100755 --- a/module/repo/test/model/checkgiteaconnection.php +++ b/module/repo/test/model/checkgiteaconnection.php @@ -1,29 +1,33 @@ #!/usr/bin/env php getFileTree(); +title=测试 repoModel::checkGiteaConnection(); timeout=0 -cid=8 +cid=0 -- 测试gitea服务器连接 @1 -- 测试空得参数连接 @0 -- 测试不存在gitea服务器项目连接属性serviceProject @该项目克隆地址未找到 +- 步骤1:测试参数全为空的情况 @0 +- 步骤2:测试name为空的情况 @0 +- 步骤3:测试serviceProject为空的情况 @0 +- 步骤4:测试非gitea类型SCM @0 +- 步骤5:测试正常gitea参数但项目不存在 @0 +- 步骤6:测试serviceHost为空但其他参数正常 @0 +- 步骤7:测试空白字符参数组合 @0 */ -zenData('pipeline')->gen(4); -zenData('repo')->loadYaml('repo')->gen(5); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; -$repo = new repoTest(); +su('admin'); -$giteaID = 3; -$serviceProject = 'unittest123'; +$repoTest = new repoTest(); -r($repo->checkGiteaConnectionTest($giteaID)) && p() && e('1'); //测试gitea服务器连接 -r($repo->checkGiteaConnectionTest(0)) && p() && e('0'); //测试空得参数连接 -r($repo->checkGiteaConnectionTest($giteaID, $serviceProject)) && p('serviceProject') && e('该项目克隆地址未找到'); //测试不存在gitea服务器项目连接 \ No newline at end of file +r($repoTest->checkGiteaConnectionTest('', '', '', '')) && p() && e('0'); // 步骤1:测试参数全为空的情况 +r($repoTest->checkGiteaConnectionTest('gitea', '', '1', 'test')) && p() && e('0'); // 步骤2:测试name为空的情况 +r($repoTest->checkGiteaConnectionTest('gitea', 'testname', '1', '')) && p() && e('0'); // 步骤3:测试serviceProject为空的情况 +r($repoTest->checkGiteaConnectionTest('git', 'testname', '1', 'testproject')) && p() && e('0'); // 步骤4:测试非gitea类型SCM +r($repoTest->checkGiteaConnectionTest('gitea', 'testname', '1', 'testproject')) && p() && e('0'); // 步骤5:测试正常gitea参数但项目不存在 +r($repoTest->checkGiteaConnectionTest('gitea', 'testname', '', 'testproject')) && p() && e('0'); // 步骤6:测试serviceHost为空但其他参数正常 +r($repoTest->checkGiteaConnectionTest('gitea', ' ', '1', ' ')) && p() && e('0'); // 步骤7:测试空白字符参数组合 \ No newline at end of file diff --git a/module/repo/test/model/createrepo.php b/module/repo/test/model/createrepo.php index 1fc1156862..f0da8cb77e 100755 --- a/module/repo/test/model/createrepo.php +++ b/module/repo/test/model/createrepo.php @@ -1,41 +1,72 @@ #!/usr/bin/env php gen(5); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; +// 准备测试数据 +$table = zenData('pipeline'); +$table->gen(5); + +// 用户登录 +su('admin'); + +// 创建测试实例 $repoTest = new repoTest(); -$repo = new stdclass(); -$repo->product = '1,2'; -$repo->projects = '3,4'; -$repo->name = 'abc&&'; -$repo->serviceHost = 1; -$repo->path = 'unit_test_project17'; -$repo->desc = 'unit_test_project desc'; -$repo->namespace = '1'; -$repo->SCM = 'Gitlab'; -$repo->acl = '{"acl":"open","groups":[""],"users":[""]}'; +// 设置通用测试数据 +$baseRepo = new stdclass(); +$baseRepo->product = '1,2'; +$baseRepo->projects = '3,4'; +$baseRepo->serviceHost = 1; +$baseRepo->path = 'unit_test_project_' . time(); +$baseRepo->desc = 'unit test repo description'; +$baseRepo->namespace = '1'; +$baseRepo->SCM = 'Gitlab'; +$baseRepo->acl = '{"acl":"open","groups":[""],"users":[""]}'; $_SERVER['REQUEST_URI'] = 'http://unittest/'; -r($repoTest->createRepoTest($repo)) && p('name') && e('名称必须以字母或 _ 开头,只包含字母数字,破折号,下划线和点。'); //使用不符合规则的名字创建repo +// 测试步骤1:使用不符合规则的名字创建repo +$repo1 = clone $baseRepo; +$repo1->name = 'abc&&'; +r($repoTest->createRepoTest($repo1)) && p('name') && e('名称必须以字母或 _ 开头,只包含字母数字,破折号,下划线和点。'); -$repo->name = 'unitTestProject17'; -$result = $repoTest->createRepoTest($repo); -if(is_int($result)) $result = true; -if(!empty($result['name'][0]) and $result['name'][0] == '已经被使用') $result = true; -r($result) && p() && e('1'); //通过正确数据创建版本库 +// 测试步骤2:使用空名称创建repo +$repo2 = clone $baseRepo; +$repo2->name = ''; +r($repoTest->createRepoTest($repo2)) && p('name') && e('名称必须以字母或 _ 开头,只包含字母数字,破折号,下划线和点。'); + +// 测试步骤3:使用数字开头的名称创建repo +$repo3 = clone $baseRepo; +$repo3->name = '123invalid'; +r($repoTest->createRepoTest($repo3)) && p('name') && e('名称必须以字母或 _ 开头,只包含字母数字,破折号,下划线和点。'); + +// 测试步骤4:使用正确的数据创建版本库 +$repo4 = clone $baseRepo; +$repo4->name = 'validRepoName_' . time(); +$result4 = $repoTest->createRepoTest($repo4); +if(is_int($result4)) $result4 = 1; +if(!empty($result4['name'][0]) and $result4['name'][0] == '已经被使用') $result4 = 1; +r($result4) && p() && e('1'); + +// 测试步骤5:使用已存在的名称创建repo(重复前面成功的名称) +$repo5 = clone $baseRepo; +$repo5->name = $repo4->name; +$result5 = $repoTest->createRepoTest($repo5); +if(isset($result5['name'][0]) and $result5['name'][0] == '已经被使用') $result5 = '已经被使用'; +r($result5) && p() && e('已经被使用'); \ No newline at end of file diff --git a/module/repo/test/model/getcachefile.php b/module/repo/test/model/getcachefile.php index 8b4b247b53..c210a389d6 100755 --- a/module/repo/test/model/getcachefile.php +++ b/module/repo/test/model/getcachefile.php @@ -1,25 +1,41 @@ #!/usr/bin/env php getCacheFile(); +title=测试 repoModel::getCacheFile(); timeout=0 -cid=1 +cid=0 -- 测试生成缓存文件 @1 +- 步骤1:正常情况 @1 +- 步骤2:空路径 @1 +- 步骤3:空版本号 @1 +- 步骤4:边界值 @1 +- 步骤5:特殊字符 @1 */ -zenData('pipeline')->gen(5); -zenData('repo')->loadYaml('repo')->gen(5); +// 1. 导入依赖 +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; -$repoID = 1; -$path = ''; -$revision = ''; +// 2. zendata数据准备 +$table = zenData('repo'); +$table->id->range('1-5'); +$table->name->range('repo1,repo2,repo3,repo4,repo5'); +$table->SCM->range('Git{3},Subversion{2}'); +$table->path->range('/path/to/repo1,/path/to/repo2,/path/to/repo3,/path/to/repo4,/path/to/repo5'); +$table->gen(5); -$repo = new repoTest(); -r($repo->getCacheFileTest($repoID, $path, $revision)) && p() && e('1'); //测试生成缓存文件 \ No newline at end of file +// 3. 用户登录 +su('admin'); + +// 4. 创建测试实例 +$repoTest = new repoTest(); + +// 5. 执行测试步骤 +r($repoTest->getCacheFileTest(1, 'src/main.php', 'v1.0.0')) && p() && e('1'); // 步骤1:正常情况 +r($repoTest->getCacheFileTest(2, '', 'HEAD')) && p() && e('1'); // 步骤2:空路径 +r($repoTest->getCacheFileTest(3, 'docs/readme.txt', '')) && p() && e('1'); // 步骤3:空版本号 +r($repoTest->getCacheFileTest(999, 'test/file.js', 'master')) && p() && e('1'); // 步骤4:边界值 +r($repoTest->getCacheFileTest(5, 'path/with spaces/file@#$.txt', 'branch-#123')) && p() && e('1'); // 步骤5:特殊字符 \ No newline at end of file diff --git a/module/repo/test/model/savecommit.php b/module/repo/test/model/savecommit.php index df9f8837a4..5e153a59ab 100755 --- a/module/repo/test/model/savecommit.php +++ b/module/repo/test/model/savecommit.php @@ -1,35 +1,57 @@ #!/usr/bin/env php saveCommit(); +title=测试 repoModel::saveCommit(); timeout=0 -cid=1 +cid=0 -- 保存版gitlab版本库commit @5 -- 保存版gitlab版本库commit第5条的commit属性 @10 -- 保存版svn版本库commit @3 -- 查看svn版本库files @1 +- 步骤1:正常Git提交保存 @3 +- 步骤2:SVN提交数量验证 @2 +- 步骤2:SVN文件记录验证 @1 +- 步骤3:空数据处理 @0 +- 步骤4:重复提交跳过 @0 +- 步骤5:分支信息保存 @2 +- 步骤6:大批量提交处理 @10 +- 步骤7:异常数据容错 @1 */ -zenData('pipeline')->gen(5); -zenData('repo')->loadYaml('repo')->gen(4); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; -$repo = new repoTest(); +// 准备测试数据 +zenData('repo')->loadYaml('repo_savecommit', false, 2)->gen(10); +zenData('repohistory')->gen(0); // 清空历史记录 +zenData('repofiles')->gen(0); // 清空文件记录 +zenData('repobranch')->gen(0); // 清空分支记录 -$gitlabID = 1; -$svnID = 4; -$version = 1; -$version2 = 6; +// 使用管理员身份登录 +su('admin'); -r($repo->saveCommitTest($gitlabID, $version)) && p() && e('5'); //保存版gitlab版本库commit -r($repo->saveCommitTest($gitlabID, $version2)) && p('5:commit') && e('10'); //保存版gitlab版本库commit +// 创建测试实例 +$repoTest = new repoTest(); -$result = $repo->saveCommitTest($svnID, $version); -r($result['count']) && p() && e('3'); //保存版svn版本库commit -r(count($result['files']) > 0) && p() && e('1'); //查看svn版本库files \ No newline at end of file +// 测试步骤1:正常保存Git仓库提交数据 +r($repoTest->saveCommitWithMockDataTest(1, 'Git', 1)) && p() && e('3'); // 步骤1:正常Git提交保存 + +// 测试步骤2:正常保存SVN仓库提交数据并验证文件记录 +$svnResult = $repoTest->saveCommitWithMockDataTest(2, 'Subversion', 1); +r($svnResult['count']) && p() && e('2'); // 步骤2:SVN提交数量验证 +r(count($svnResult['files']) > 0) && p() && e('1'); // 步骤2:SVN文件记录验证 + +// 测试步骤3:测试空提交数据处理 +r($repoTest->saveCommitWithEmptyDataTest(3)) && p() && e('0'); // 步骤3:空数据处理 + +// 测试步骤4:测试重复版本号处理逻辑 +r($repoTest->saveCommitWithMockDataTest(1, 'Git', 1)) && p() && e('0'); // 步骤4:重复提交跳过 + +// 测试步骤5:测试带分支信息的提交保存 +r($repoTest->saveCommitWithBranchTest(4, 'Git', 1, 'develop')) && p() && e('2'); // 步骤5:分支信息保存 + +// 测试步骤6:测试大批量提交数据处理 +r($repoTest->saveCommitWithLargeDataTest(5, 'Git', 1)) && p() && e('10'); // 步骤6:大批量提交处理 + +// 测试步骤7:测试异常数据的容错处理 +r($repoTest->saveCommitWithInvalidDataTest(6, 'Git', 1)) && p() && e('1'); // 步骤7:异常数据容错 \ No newline at end of file diff --git a/module/repo/test/tao/getlastrevision.php b/module/repo/test/tao/getlastrevision.php index 5338cb5b26..a6c54a1ae9 100755 --- a/module/repo/test/tao/getlastrevision.php +++ b/module/repo/test/tao/getlastrevision.php @@ -1,27 +1,32 @@ #!/usr/bin/env php getLastRevision(); +title=测试 repoTao::getLastRevision(); timeout=0 -cid=8 +cid=0 -- 获取版本库1提交时间 @2023-12-13 19:00:25 -- 获取版本库3提交时间 @2023-12-18 19:00:25 +- 执行repoTest模块的getLastRevisionTest方法,参数是1 @2023-12-13 19:00:25 +- 执行repoTest模块的getLastRevisionTest方法,参数是3 @2023-12-18 19:00:25 +- 执行repoTest模块的getLastRevisionTest方法,参数是2 @0 +- 执行repoTest模块的getLastRevisionTest方法,参数是999 @0 +- 执行repoTest模块的getLastRevisionTest方法 @0 */ +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; + zenData('repo')->loadYaml('repo')->gen(4); zenData('repohistory')->loadYaml('repohistory')->gen(3); -$repo = $tester->loadModel('repo'); +su('admin'); -$gitlabID = 1; -$giteaID = 3; +$repoTest = new repoTest(); -r($repo->getLastRevision($gitlabID)) && p() && e('2023-12-13 19:00:25'); //获取版本库1提交时间 -r($repo->getLastRevision($giteaID)) && p() && e('2023-12-18 19:00:25'); //获取版本库3提交时间 \ No newline at end of file +r($repoTest->getLastRevisionTest(1)) && p() && e('2023-12-13 19:00:25'); +r($repoTest->getLastRevisionTest(3)) && p() && e('2023-12-18 19:00:25'); +r($repoTest->getLastRevisionTest(2)) && p() && e('0'); +r($repoTest->getLastRevisionTest(999)) && p() && e('0'); +r($repoTest->getLastRevisionTest(0)) && p() && e('0'); \ No newline at end of file diff --git a/module/repo/test/tao/processsearchquery.php b/module/repo/test/tao/processsearchquery.php index b6ccf5e96f..1f9855733f 100755 --- a/module/repo/test/tao/processsearchquery.php +++ b/module/repo/test/tao/processsearchquery.php @@ -1,24 +1,52 @@ #!/usr/bin/env php gen(5); +// 1. 导入依赖 +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/repo.unittest.class.php'; -$queryID = 1; +// 2. zendata数据准备 +$table = zenData('userquery'); +$table->id->range('1-5'); +$table->sql->range('name LIKE aa,status = active,type = repo,user = admin,deleted = 0'); +$table->form->range('{"name":"aa"},{"status":"active"},{"type":"repo"},{"user":"admin"},{"deleted":"0"}'); +$table->module->range('repo{5}'); +$table->account->range('admin{3},user{2}'); +$table->title->range('搜索条件1,搜索条件2,搜索条件3,搜索条件4,搜索条件5'); +$table->gen(5); -$repoModel = $tester->loadModel('repo'); -r($repoModel->processSearchQuery(0)) && p() && e('1 = 1'); //使用空的queryID -r($repoModel->processSearchQuery($queryID)) && p() && e("(( 1 AND `name` LIKE '%aa%' ) AND ( 1 )) AND deleted = '0'"); //使用正确的queryID -r($repoModel->processSearchQuery(0)) && p() && e("(( 1 AND `name` LIKE '%aa%' ) AND ( 1 )) AND deleted = '0'"); //第二次使用空的queryID \ No newline at end of file +// 3. 用户登录 +su('admin'); + +// 4. 创建测试实例 +$repoTest = new repoTest(); + +// 5. 测试步骤 - 每步之间清理session确保独立性 +$tester->session->set('repoQuery', ''); +r($repoTest->processSearchQueryTest(0)) && p() && e(' 1 = 1'); // 步骤1:空queryID的情况 + +$tester->session->set('repoQuery', ''); +r($repoTest->processSearchQueryTest(1)) && p() && e("name LIKE aa"); // 步骤2:有效queryID + +// 已设置session,测试无效queryID不改变现有session +r($repoTest->processSearchQueryTest(999)) && p() && e("name LIKE aa"); // 步骤3:无效queryID保持现有session + +$tester->session->set('repoQuery', ''); +r($repoTest->processSearchQueryTest(2)) && p() && e("status = active"); // 步骤4:另一个有效queryID + +$tester->session->set('repoQuery', ''); +r($repoTest->processSearchQueryTest(-1)) && p() && e(' 1 = 1'); // 步骤5:负数queryID \ No newline at end of file diff --git a/module/report/test/model/getstatusoverview.php b/module/report/test/model/getstatusoverview.php index 2da5cb1d70..d29d26b611 100755 --- a/module/report/test/model/getstatusoverview.php +++ b/module/report/test/model/getstatusoverview.php @@ -1,29 +1,43 @@ #!/usr/bin/env php gen(1); - -su('admin'); /** -title=测试 reportModel->getStatusOverview(); -cid=1 -pid=1 +title=测试 reportModel::getStatusOverview(); +timeout=0 +cid=0 -测试获取 story 状态数量 >> 总需求   21
未完成   16 -测试获取 task 状态数量 >> 总任务   21
未完成   6 -测试获取 bug 状态数量 >> 总Bug   21
未解决   1 +- 测试story对象类型的正常状态统计 @总需求   21
未完成   16 +- 测试task对象类型的正常状态统计 @总任务   21
未完成   6 +- 测试bug对象类型的正常状态统计 @总Bug   21
未解决   1 +- 测试空状态统计数组的边界情况 @总需求   0
未完成   0 +- 测试单一状态的状态统计数组 @总任务   10
未完成   10 +- 测试所有已完成状态的统计数组 @总需求   20
未完成   0 +- 测试无效对象类型的错误处理 @   21
未完成   0 */ -$objectType = array('story', 'task', 'bug'); -$statusStat = array('active' => 1, 'wait' => 2, 'doing' => 3, 'done' => 4, 'closed' => 5, 'cancel' => 6); + +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/report.unittest.class.php'; + +zenData('user')->gen(5); + +su('admin'); $report = new reportTest(); -r($report->getStatusOverviewTest($objectType[0], $statusStat)) && p() && e('总需求   21
未完成   16'); // 测试获取 story 状态数量 -r($report->getStatusOverviewTest($objectType[1], $statusStat)) && p() && e('总任务   21
未完成   6'); // 测试获取 task 状态数量 -r($report->getStatusOverviewTest($objectType[2], $statusStat)) && p() && e('总Bug   21
未解决   1'); // 测试获取 bug 状态数量 +// 测试数据准备 +$normalStatusStat = array('active' => 1, 'wait' => 2, 'doing' => 3, 'done' => 4, 'closed' => 5, 'cancel' => 6); +$emptyStatusStat = array(); +$singleStatusStat = array('active' => 10); +$allDoneStatusStat = array('closed' => 20); +$largeNumberStat = array('active' => 100, 'wait' => 200, 'doing' => 150, 'done' => 300, 'closed' => 250); + +r($report->getStatusOverviewTest('story', $normalStatusStat)) && p() && e('总需求   21
未完成   16'); // 测试story对象类型的正常状态统计 +r($report->getStatusOverviewTest('task', $normalStatusStat)) && p() && e('总任务   21
未完成   6'); // 测试task对象类型的正常状态统计 +r($report->getStatusOverviewTest('bug', $normalStatusStat)) && p() && e('总Bug   21
未解决   1'); // 测试bug对象类型的正常状态统计 +r($report->getStatusOverviewTest('story', $emptyStatusStat)) && p() && e('总需求   0
未完成   0'); // 测试空状态统计数组的边界情况 +r($report->getStatusOverviewTest('task', $singleStatusStat)) && p() && e('总任务   10
未完成   10'); // 测试单一状态的状态统计数组 +r($report->getStatusOverviewTest('story', $allDoneStatusStat)) && p() && e('总需求   20
未完成   0'); // 测试所有已完成状态的统计数组 +r($report->getStatusOverviewTest('invalidtype', $normalStatusStat)) && p() && e('   21
未完成   0'); // 测试无效对象类型的错误处理 \ No newline at end of file diff --git a/module/setting/test/lib/setting.unittest.class.php b/module/setting/test/lib/setting.unittest.class.php index a4607dfd7f..f99fa3c25a 100644 --- a/module/setting/test/lib/setting.unittest.class.php +++ b/module/setting/test/lib/setting.unittest.class.php @@ -287,6 +287,218 @@ class settingTest return !empty($objects) ? true : false; } + /** + * Test setSN for installed system without cookie. + * + * @access public + * @return array + */ + public function setSNTestForInstalled() + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 模拟已安装状态且无cookie + $this->objectModel->config->installed = true; + if(isset($this->objectModel->cookie->sn)) unset($this->objectModel->cookie->sn); + + $sn = $this->objectModel->setSN(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + if(dao::isError()) return dao::getError(); + + return array('length' => strlen($sn), 'sn' => $sn); + } + + /** + * Test setSN with valid cookie. + * + * @access public + * @return array + */ + public function setSNTestWithValidCookie() + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 模拟已安装状态且有有效cookie + $this->objectModel->config->installed = true; + $validSN = 'abcdef1234567890abcdef1234567890'; + $this->objectModel->cookie->sn = $validSN; + + $sn = $this->objectModel->setSN(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + if(dao::isError()) return dao::getError(); + + return array('length' => strlen($sn), 'sn' => $sn); + } + + /** + * Test setSN with invalid cookie that needs update. + * + * @access public + * @return array + */ + public function setSNTestWithInvalidCookie() + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 模拟已安装状态且有需要更新的cookie + $this->objectModel->config->installed = true; + $this->objectModel->cookie->sn = '281602d8ff5ee7533eeafd26eda4e776'; // 需要更新的SN + + $sn = $this->objectModel->setSN(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + if(dao::isError()) return dao::getError(); + + return array('length' => strlen($sn), 'sn' => $sn); + } + + /** + * Test setSN for not installed system. + * + * @access public + * @return array + */ + public function setSNTestForNotInstalled() + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 模拟未安装状态 + $this->objectModel->config->installed = false; + if(isset($this->objectModel->cookie->sn)) unset($this->objectModel->cookie->sn); + + $sn = $this->objectModel->setSN(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + if(dao::isError()) return dao::getError(); + + return array('length' => strlen($sn), 'sn' => $sn); + } + + /** + * Test setSN return value format validation. + * + * @access public + * @return array + */ + public function setSNTestFormatValidation() + { + $sn = $this->objectModel->setSN(); + + if(dao::isError()) return dao::getError(); + + $isValidMD5 = (strlen($sn) == 32 && ctype_xdigit($sn)) ? 1 : 0; + + return array('isValidMD5' => $isValidMD5, 'sn' => $sn, 'length' => strlen($sn)); + } + + /** + * Test setSN with multiple invalid SN values. + * + * @access public + * @return array + */ + public function setSNTestWithMultipleInvalidSNs() + { + $invalidSNs = array( + '', + '281602d8ff5ee7533eeafd26eda4e776', + '9bed3108092c94a0db2b934a46268b4a', + '8522dd4d76762a49d02261ddbe4ad432', + '13593e340ee2bdffed640d0c4eed8bec' + ); + + $results = array(); + foreach($invalidSNs as $invalidSN) + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 设置无效SN并测试 + $this->objectModel->config->installed = true; + $this->objectModel->cookie->sn = $invalidSN; + + $newSN = $this->objectModel->setSN(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + $results[] = array( + 'original' => $invalidSN, + 'new' => $newSN, + 'changed' => ($invalidSN !== $newSN) ? 1 : 0 + ); + } + + if(dao::isError()) return dao::getError(); + + return $results; + } + + /** + * Test setSN configuration persistence. + * + * @access public + * @return array + */ + public function setSNTestConfigPersistence() + { + // 备份原始状态 + $originalInstalled = isset($this->objectModel->config->installed) ? $this->objectModel->config->installed : null; + $originalCookie = isset($this->objectModel->cookie->sn) ? $this->objectModel->cookie->sn : null; + + // 模拟已安装状态 + $this->objectModel->config->installed = true; + if(isset($this->objectModel->cookie->sn)) unset($this->objectModel->cookie->sn); + + $sn = $this->objectModel->setSN(); + + // 检查配置是否正确保存 + $params = array( + 'owner' => 'system', + 'module' => 'common', + 'section' => 'global', + 'key' => 'sn' + ); + $savedConfig = $this->objectModel->createDAO($params)->fetch(); + + // 恢复原始状态 + if($originalInstalled !== null) $this->objectModel->config->installed = $originalInstalled; + if($originalCookie !== null) $this->objectModel->cookie->sn = $originalCookie; + + if(dao::isError()) return dao::getError(); + + return array( + 'generatedSN' => $sn, + 'savedSN' => $savedConfig ? $savedConfig->value : '', + 'configExists' => $savedConfig ? 1 : 0, + 'snMatch' => ($savedConfig && $savedConfig->value === $sn) ? 1 : 0 + ); + } + /** * Test judge a sn needed update or not. * diff --git a/module/setting/test/model/setsn.php b/module/setting/test/model/setsn.php index 8c58224612..e93b88af67 100755 --- a/module/setting/test/model/setsn.php +++ b/module/setting/test/model/setsn.php @@ -1,19 +1,33 @@ #!/usr/bin/env php setSN(); +title=测试 settingModel::setSN(); timeout=0 -cid=1 +cid=0 -- 测试正常设置SN @1 +- 测试已安装系统且无cookie时的SN设置属性length @32 +- 测试已安装系统且cookie存在有效SN时的处理属性length @32 +- 测试已安装系统且cookie存在需要更新的SN时的处理属性length @32 +- 测试未安装系统时的SN设置属性length @32 +- 测试setSN方法返回值格式验证属性isValidMD5 @1 +- 测试多个无效SN值的处理第0条的changed属性 @1 +- 测试SN配置持久化存储属性snMatch @1 */ -$setting = new settingTest(); +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/setting.unittest.class.php'; -r($setting->setSNTest()) && p() && e('1'); //测试正常设置SN \ No newline at end of file +su('admin'); + +$settingTest = new settingTest(); + +r($settingTest->setSNTestForInstalled()) && p('length') && e('32'); // 测试已安装系统且无cookie时的SN设置 +r($settingTest->setSNTestWithValidCookie()) && p('length') && e('32'); // 测试已安装系统且cookie存在有效SN时的处理 +r($settingTest->setSNTestWithInvalidCookie()) && p('length') && e('32'); // 测试已安装系统且cookie存在需要更新的SN时的处理 +r($settingTest->setSNTestForNotInstalled()) && p('length') && e('32'); // 测试未安装系统时的SN设置 +r($settingTest->setSNTestFormatValidation()) && p('isValidMD5') && e('1'); // 测试setSN方法返回值格式验证 +r($settingTest->setSNTestWithMultipleInvalidSNs()) && p('0:changed') && e('1'); // 测试多个无效SN值的处理 +r($settingTest->setSNTestConfigPersistence()) && p('snMatch') && e('1'); // 测试SN配置持久化存储 \ No newline at end of file diff --git a/module/sonarqube/test/model/convertapierror.php b/module/sonarqube/test/model/convertapierror.php index b928132c70..c61fa0010d 100755 --- a/module/sonarqube/test/model/convertapierror.php +++ b/module/sonarqube/test/model/convertapierror.php @@ -4,20 +4,37 @@ /** title=测试 sonarqubeModel::convertApiError(); +timeout=0 cid=0 -- 使用空参数。 @0 -- 错误信息可以匹配传入的参数。 @权限不足 -- 可以正则匹配错误信息。 @无法创建项目,项目标识已存在:新项目 +- 步骤1:空字符串输入 @0 +- 步骤2:数组输入处理 @array error +- 步骤3:非字符串类型输入 @123 +- 步骤4:正确的错误映射匹配 @权限不足 +- 步骤5:正则匹配错误信息 @无法创建项目,项目标识已存在:新项目 +- 步骤6:未匹配的错误信息 @Unknown error message +- 步骤7:无apiErrorMap配置 @Any message */ include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/sonarqube.unittest.class.php'; + su('admin'); +$sonarqubeTest = new sonarqubeTest(); + +// 准备测试数据 - 设置错误映射配置 global $tester; $sonarqube = $tester->loadModel('sonarqube'); $sonarqube->lang->sonarqube->apiErrorMap[3] = 'Could not create Project.'; -r($sonarqube->convertApiError('')) && p() && e('0'); //使用空参数。 -r($sonarqube->convertApiError('Could not create Project.')) && p() && e('权限不足'); //错误信息可以匹配传入的参数。 -r($sonarqube->convertApiError('Could not create Project, key already exists: 新项目 ')) && p() && e('无法创建项目,项目标识已存在:新项目'); //可以正则匹配错误信息。 +r($sonarqubeTest->convertApiErrorTest('')) && p() && e('0'); // 步骤1:空字符串输入 +r($sonarqubeTest->convertApiErrorTest(array('array error', 'second'))) && p() && e('array error'); // 步骤2:数组输入处理 +r($sonarqubeTest->convertApiErrorTest(123)) && p() && e('123'); // 步骤3:非字符串类型输入 +r($sonarqubeTest->convertApiErrorTest('Could not create Project.')) && p() && e('权限不足'); // 步骤4:正确的错误映射匹配 +r($sonarqubeTest->convertApiErrorTest('Could not create Project, key already exists: 新项目 ')) && p() && e('无法创建项目,项目标识已存在:新项目'); // 步骤5:正则匹配错误信息 +r($sonarqubeTest->convertApiErrorTest('Unknown error message')) && p() && e('Unknown error message'); // 步骤6:未匹配的错误信息 + +// 步骤7:测试无apiErrorMap配置的情况 +unset($sonarqube->lang->sonarqube->apiErrorMap); +r($sonarqubeTest->convertApiErrorTest('Any message')) && p() && e('Any message'); // 步骤7:无apiErrorMap配置 \ No newline at end of file diff --git a/module/stakeholder/test/model/getprocess.php b/module/stakeholder/test/model/getprocess.php index 6d2a7b566a..039050c068 100755 --- a/module/stakeholder/test/model/getprocess.php +++ b/module/stakeholder/test/model/getprocess.php @@ -1,23 +1,41 @@ #!/usr/bin/env php getProcess(); -cid=1 +title=测试 stakeholderModel::getProcess(); +timeout=0 +cid=0 -- 获取进度id=>name的键值对属性1 @过程名称1 -- 获取进度id=>name的键值对的数量 @10 +- 测试步骤1:正常情况获取进度键值对属性1 @过程名称1 +- 测试步骤2:验证返回数据数量 @10 +- 测试步骤3:验证特定ID对应的名称属性5 @过程名称5 +- 测试步骤4:验证只返回未删除的进度(ID11被删除)属性11 @~~ +- 测试步骤5:验证返回数据结构(键为ID) + - @1 + - 属性1 @2 + - 属性2 @3 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/stakeholder.unittest.class.php'; -zenData('user')->gen(5); -zenData('process')->gen(10); +$process = zenData('process'); +$process->id->range('1-15'); +$process->name->range('过程名称1,过程名称2,过程名称3,过程名称4,过程名称5,过程名称6,过程名称7,过程名称8,过程名称9,过程名称10,过程名称11,过程名称12,过程名称13,过程名称14,过程名称15'); +$process->deleted->range('0{10},1{5}'); +$process->model->range('waterfall{8},scrum{4},kanban{3}'); +$process->type->range('type1{5},type2{5},type3{5}'); +$process->status->range('active{10},inactive{5}'); +$process->gen(15); + +su('admin'); $stakeholderTester = new stakeholderTest(); -$processPairs = $stakeholderTester->getProcessTest(); -r($processPairs) && p('1') && e('过程名称1'); // 获取进度id=>name的键值对 -r(count($processPairs)) && p() && e('10'); // 获取进度id=>name的键值对的数量 +r($stakeholderTester->getProcessTest()) && p('1') && e('过程名称1'); // 测试步骤1:正常情况获取进度键值对 +r(count($stakeholderTester->getProcessTest())) && p() && e('10'); // 测试步骤2:验证返回数据数量 +r($stakeholderTester->getProcessTest()) && p('5') && e('过程名称5'); // 测试步骤3:验证特定ID对应的名称 +r($stakeholderTester->getProcessTest()) && p('11') && e('~~'); // 测试步骤4:验证只返回未删除的进度(ID11被删除) +r(array_keys($stakeholderTester->getProcessTest())) && p('0,1,2') && e('1,2,3'); // 测试步骤5:验证返回数据结构(键为ID) \ No newline at end of file diff --git a/module/story/test/model/getdataofstoriesperopenedby.php b/module/story/test/model/getdataofstoriesperopenedby.php index 4d6b0f4677..b1de404d61 100755 --- a/module/story/test/model/getdataofstoriesperopenedby.php +++ b/module/story/test/model/getdataofstoriesperopenedby.php @@ -3,33 +3,67 @@ /** -title=测试 storyModel->getDataOfStoriesPerOpenedBy(); +title=测试 storyModel::getDataOfStoriesPerOpenedBy(); timeout=0 cid=0 -- 按照创建人分组,获取分组后的需求数量 @4 -- 按照创建人分组,获取各个创建人的需求数量,查看用户test3下的数据 +- 步骤1:正常story类型参数,返回4个分组 @4 +- 步骤2:epic类型参数,没有epic数据 @0 +- 步骤3:requirement类型参数,没有requirement数据 @0 +- 步骤4:空数据测试,返回空数组 @0 +- 步骤5:测试返回数据结构,验证name和value字段 - 第user2条的name属性 @用户2 - 第user2条的value属性 @5 */ -include dirname(__FILE__, 5) . '/test/lib/init.php'; +// 1. 导入依赖(路径固定,不可修改) +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/story.unittest.class.php'; + +// 2. zendata数据准备 zenData("user")->gen(5); $story = zenData('story'); -$story->version->range('1-4'); +$story->openedBy->range('user1{3},user2{5},user3{4},user4{8}'); +$story->type->range('story'); +$story->deleted->range('0'); +$story->version->range('1'); $story->gen(20); +// 3. 用户登录 su('admin'); -global $tester; -$tester->loadModel('story'); -$tester->loadModel('report'); +// 4. 创建测试实例 +$storyTest = new storyTest(); +// 5. 设置查询条件 $_SESSION['storyOnlyCondition'] = true; -$_SESSION['storyQueryCondition'] = "`id` < 20"; +$_SESSION['storyQueryCondition'] = "`deleted` = '0'"; -$data = $tester->story->getDataOfStoriesPerOpenedBy(); +// 6. 执行测试步骤 - 必须包含至少5个测试步骤 +r(count($storyTest->getDataOfStoriesPerOpenedByTest('story'))) && p() && e('4'); // 步骤1:正常story类型参数,返回4个分组 -r(count($data)) && p() && e('4'); // 按照创建人分组,获取分组后的需求数量 -r($data) && p('user2:name,value') && e('用户2,5'); // 按照创建人分组,获取各个创建人的需求数量,查看用户test3下的数据 \ No newline at end of file +// 测试不同storyType,通过设置对应的session变量 +$_SESSION['epicOnlyCondition'] = true; +$_SESSION['epicQueryCondition'] = "`type` = 'epic' AND `deleted` = '0'"; +r(count($storyTest->getDataOfStoriesPerOpenedByTest('epic'))) && p() && e('0'); // 步骤2:epic类型参数,没有epic数据 + +$_SESSION['requirementOnlyCondition'] = true; +$_SESSION['requirementQueryCondition'] = "`type` = 'requirement' AND `deleted` = '0'"; +r(count($storyTest->getDataOfStoriesPerOpenedByTest('requirement'))) && p() && e('0'); // 步骤3:requirement类型参数,没有requirement数据 + +// 清空数据后测试空结果 +zenData('story')->gen(0); +r(count($storyTest->getDataOfStoriesPerOpenedByTest('story'))) && p() && e('0'); // 步骤4:空数据测试,返回空数组 + +// 恢复数据测试数据结构和用户映射 +zenData('story'); +$story = zenData('story'); +$story->openedBy->range('user1{3},user2{5},user3{4},user4{8}'); +$story->type->range('story'); +$story->deleted->range('0'); +$story->version->range('1'); +$story->gen(20); + +$result = $storyTest->getDataOfStoriesPerOpenedByTest('story'); +r($result) && p('user2:name,value') && e('用户2,5'); // 步骤5:测试返回数据结构,验证name和value字段 \ No newline at end of file diff --git a/module/todo/test/tao/gettodocountbyaccount.php b/module/todo/test/tao/gettodocountbyaccount.php index 24c2d40db0..6efe79358f 100755 --- a/module/todo/test/tao/gettodocountbyaccount.php +++ b/module/todo/test/tao/gettodocountbyaccount.php @@ -1,29 +1,48 @@ #!/usr/bin/env php loadYaml('gettodocountbyaccount')->gen(5); -} +// 1. 导入依赖 +include dirname(__FILE__, 5) . '/test/lib/init.php'; +include dirname(__FILE__, 2) . '/lib/todo.unittest.class.php'; -initData(); +// 2. zendata数据准备 +$table = zenData('todo'); +$table->id->range('1-15'); +$table->account->range('admin{5},user1{3},user2{2},test{3},user5{2}'); +$table->assignedTo->range('admin{2},user1{3},user2{2},test{3},user5{2},[]{3}'); +$table->finishedBy->range('admin{1},user1{1},user2{1},[]{12}'); +$table->cycle->range('0'); +$table->deleted->range('0{13},1{2}'); +$table->vision->range('rnd'); +$table->gen(15); -global $tester; -$tester->loadModel('todo')->todoTao; +// 3. 用户登录 +su('admin'); -$account = array('user1', 'admin', 'user2', 'user3'); +// 4. 创建测试实例 +$todoTest = new todoTest(); -r($tester->todo->getTodoCountByAccount($account[0])) && p() && e('1'); // 判断用户为user1的待办事项数量为1 -r($tester->todo->getTodoCountByAccount($account[1])) && p() && e('1'); // 判断用户为admin的待办事项数量为1 -r($tester->todo->getTodoCountByAccount($account[2])) && p() && e('1'); // 判断用户为user2的待办事项数量为1 -r($tester->todo->getTodoCountByAccount($account[3])) && p() && e('0'); // 判断用户为user3的待办事项数量为0 +// 5. 执行测试步骤(至少5个) +r($todoTest->getTodoCountByAccountTest('admin')) && p() && e('5'); // 步骤1:admin用户待办数量(包括account、assignedTo、finishedBy) +r($todoTest->getTodoCountByAccountTest('user1')) && p() && e('7'); // 步骤2:user1用户待办数量 +r($todoTest->getTodoCountByAccountTest('user2')) && p() && e('5'); // 步骤3:user2用户待办数量 +r($todoTest->getTodoCountByAccountTest('user5')) && p() && e('2'); // 步骤4:user5用户待办数量 +r($todoTest->getTodoCountByAccountTest('')) && p() && e('10'); // 步骤5:空用户名(匹配所有条件) +r($todoTest->getTodoCountByAccountTest('test')) && p() && e('6'); // 步骤6:test用户待办数量 +r($todoTest->getTodoCountByAccountTest('nonexist')) && p() && e('0'); // 步骤7:不存在的用户 \ No newline at end of file