PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/functions/specview.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 1066 lines | 553 code | 104 blank | 409 comment | 118 complexity | a0b2a1d61a975ec4ebf86d1eedbd94bd MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * TestLink Open Source Project - http://testlink.sourceforge.net/
  4. * This script is distributed under the GNU General Public License 2 or later.
  5. *
  6. * @package TestLink
  7. * @author Francisco Mancardi (francisco.mancardi@gmail.com)
  8. * @copyright 2004-2009, TestLink community
  9. * @version CVS: $Id: specview.php,v 1.62 2010/07/26 19:01:15 asimon83 Exp $
  10. * @link http://www.teamst.org/index.php
  11. *
  12. * @internal Revisions:
  13. *
  14. * 20100726 - asimon - BUGID 3628: in addLinkedVersionsInfo(), a missing [0] in condition
  15. * caused missing priority
  16. * 20100721 - asimon - BUGID 3406 - added $options for new user assignments per build to
  17. * gen_spec_view(), getFilteredLinkedVersions(),
  18. * and keywordFilteredSpecView()
  19. *
  20. * 20100417 - franciscom - BUGID 2498 Add test case to test plan - Filter Test Cases based on Test Importance
  21. * 20100411 - franciscom - BUGID 2797 - filter by test case execution type
  22. *
  23. * 20100218 - asimon - BUGID 3026 - added parameter $testcaseFilter on keywordFilteredSpecView
  24. * to include functionality previously used on tc_exec_assignment.php
  25. * to show only testcases present in filter argument
  26. * 20100119 - franciscom - addCustomFieldsToView() - missing work on platforms
  27. * 20090808 - franciscom - gen_spec_view() interface changes + refactoring
  28. * 20090325 - franciscom - added new info about when and who has linked a tcversion
  29. * 20090325 - franciscom - BUGID - better implementation of BUGID 1497
  30. * 20081109 - franciscom - fixed filter on getTestSpecFromNode()
  31. * fixed minor bug on $tsuite_tcqty processing
  32. * added new value for spec_view_type='uncoveredtestcases'.
  33. *
  34. * 20081030 - franciscom - created removeEmptyTestSuites(), removeEmptyBranches() to refactor.
  35. * refactored use of tproject_id on gen_spec_view()
  36. *
  37. * 20081019 - franciscom - removed new option to prune empty test suites
  38. * till we understand were this will be used.
  39. * In today implementation causes problems
  40. * Added logic to compute total count of test cases
  41. * for every test suite in a branch, to avoid use
  42. * of map_node_tccount argument
  43. *
  44. * 20080919 - franciscom - BUGID 1716
  45. * 20080811 - franciscom - BUGID 1650 (REQ)
  46. * 20080422 - franciscom - BUGID 1497
  47. * Suggested by Martin Havlat execution order will be set to external_id * 10
  48. * for test cases not linked yet
  49. *
  50. **/
  51. /**
  52. * Generate data for Test Specification
  53. *
  54. * @param string $spec_view_type can get one of the following values:
  55. * 'testproject','testplan','uncoveredtestcases'
  56. *
  57. * This setting change the processing done
  58. * to get the keywords.
  59. * And indicates the type of id (testproject/testplan)
  60. * contained in the argument tobj_id.
  61. * when using uncoveredtestcases tobj_id = testproject id
  62. * @param integer $tobj_id can be a testproject id, or testplan id.
  63. * @param integer $id node id, that we are using as root for the view we want to build
  64. * @param string $name
  65. * @param array $linked_items map where key=testcase_id
  66. * value map with following keys:
  67. * [testsuite_id] => 2732
  68. * [tc_id] => 2733
  69. * [z] => 100 ---> nodes_hierarchy.order
  70. * [name] => TC1
  71. * [tcversion_id] => 2734
  72. * [feature_id] => 9 --->> testplan_tcversions.ID
  73. * [execution_order] => 10
  74. * [version] => 1
  75. * [active] => 1
  76. * [external_id] => 1
  77. * [exec_id] => 1
  78. * [tcversion_number] => 1
  79. * [executed] => 2734
  80. * [exec_on_tplan] => 2735
  81. * [user_id] =>
  82. * [type] =>
  83. * [status] =>
  84. * [assigner_id] =>
  85. * [urgency] => 2 IMPORTANT: exists ONLY FOR LINKED TEST CASES
  86. * [exec_status] => b
  87. * [priority] => 4 // urgency*importance IMPORTANT: exists ONLY FOR LINKED TEST CASES
  88. *
  89. * @param array $map_node_tccount
  90. * @TODO probably this argument ($map_node_tccount) is not needed, but it will depend
  91. * of how this feature (gen_spec_view) will be used on other TL areas.
  92. *
  93. * @param map $filters keys
  94. * [keyword_id] default 0
  95. * [tcase_id] default null, can be an array
  96. *
  97. * @param map $options keys
  98. * [write_button_only_if_linked] default 0
  99. * [prune_unlinked_tcversions]: default 0.
  100. * Useful when working on spec_view_type='testplan'.
  101. * 1 -> will return only linked tcversion
  102. * 0 -> returns all test cases specs.
  103. * [add_custom_fields]: default=0
  104. * useful when working on spec_view_type='testproject'
  105. * when doing test case assign to test plans.
  106. * 1 -> for every test case cfields of area 'testplan_design'
  107. * will be fetched and displayed.
  108. * 0 -> do nothing
  109. *
  110. * [$tproject_id]: default = null
  111. * useful to improve performance in custom field method calls
  112. * when add_custom_fields=1.
  113. *
  114. *
  115. * @return array every element is an associative array with the following
  116. * structure: (to get last updated info add debug code and print_r returned value)
  117. * [testsuite] => Array( [id] => 28
  118. * [name] => TS1 )
  119. * [testcases] => Array( [2736] => Array
  120. * (
  121. * [id] => 2736
  122. * [name] => TC2
  123. * [tcversions] => Array
  124. * (
  125. * [2738] => 2 // key=tcversion id,value=version
  126. * [2737] => 1
  127. * )
  128. * [tcversions_active_status] => Array
  129. * (
  130. * [2738] => 1 // key=tcversion id,value=active status
  131. * [2737] => 1
  132. * )
  133. * [tcversions_execution_type] => Array
  134. * (
  135. * [2738] => 1
  136. * [2737] => 2
  137. * )
  138. * [tcversions_qty] => 2
  139. * [linked_version_id] => 2737
  140. * [executed] => no
  141. * [user_id] => 0 ---> !=0 if execution has been assigned
  142. * [feature_id] => 12 ---> testplan_tcversions.id
  143. * [execution_order] => 20
  144. * [external_id] => 2
  145. * [linked_ts] => 2009-06-10 23:00
  146. * [linked_by] => 2
  147. * [priority] => HIGH, MEDIUM or LOW
  148. * )
  149. * [81] => Array( [id] => 81
  150. * [name] => TC88)
  151. * ...
  152. * )
  153. * [level] =
  154. * [write_buttons] => yes or no
  155. * level and write_buttons are used to generate the user interface
  156. *
  157. * Warning:
  158. * if the root element of the spec_view, has 0 test => then the default
  159. * structure is returned ( $result = array('spec_view'=>array(), 'num_tc' => 0))
  160. *
  161. * @internal Revisions:
  162. *
  163. * 20100721 - asimon - BUGID 3406 - added user_assignments_per_build to options
  164. *
  165. * 20090808 - franciscom - changed interface to reduce number of arguments
  166. *
  167. * 20070707 - franciscom - BUGID 921 - problems with display order in execution screen
  168. * 20070630 - franciscom - added new logic to include in for inactive test cases, testcase version id.
  169. * This is needed to show testcases linked to testplans, but after be linked to
  170. * test plan, has been set to inactive on test project.
  171. * 20061105 - franciscom - added new data on output: [tcversions_qty]
  172. * used in the logic to filter out inactive tcversions,
  173. * and inactive test cases.
  174. * Counts the quantity of active versions of a test case.
  175. * If 0 => test case is considered INACTIVE
  176. * 20090625 - Eloff - added priority output
  177. */
  178. function gen_spec_view(&$db, $spec_view_type='testproject', $tobj_id, $id, $name, &$linked_items,
  179. $map_node_tccount, $filters=null, $options = null, $tproject_id = null)
  180. {
  181. $out = array();
  182. $result = array('spec_view'=>array(), 'num_tc' => 0, 'has_linked_items' => 0);
  183. $my = array();
  184. $my['options'] = array('write_button_only_if_linked' => 0,
  185. 'prune_unlinked_tcversions' => 0,
  186. 'add_custom_fields' => 0)
  187. + (array)$options;
  188. // BUGID 2797 - filter by test case execution type
  189. $my['filters'] = array('keywords' => 0, 'testcases' => null ,'exec_type' => null, 'importance' => null);
  190. foreach( $my as $key => $settings)
  191. {
  192. if( !is_null($$key) && is_array($$key) )
  193. {
  194. $my[$key] = array_merge($my[$key],$$key);
  195. }
  196. }
  197. $write_status = $my['options']['write_button_only_if_linked'] ? 'no' : 'yes';
  198. $is_tplan_view_type=$spec_view_type == 'testplan' ? 1 : 0;
  199. $is_uncovered_view_type = ($spec_view_type == 'uncoveredtestcases') ? 1 : 0;
  200. if( !$is_tplan_view_type && is_null($tproject_id) )
  201. {
  202. $tproject_id = $tobj_id;
  203. }
  204. $testplan_id = $is_tplan_view_type ? $tobj_id : null;
  205. $tcase_mgr = new testcase($db);
  206. $hash_descr_id = $tcase_mgr->tree_manager->get_available_node_types();
  207. $hash_id_descr = array_flip($hash_descr_id);
  208. // BUGID 2797 - filter by test case execution type
  209. $pfFilters = array('keyword_id' => $my['filters']['keywords'],
  210. 'tcase_id' => $my['filters']['testcases'],
  211. 'tcase_node_type_id' => $hash_descr_id['testcase'],
  212. 'execution_type' => $my['filters']['exec_type'],
  213. 'importance' => $my['filters']['importance'] );
  214. // $test_spec = getTestSpecFromNode($db,$tcase_mgr,$linked_items,$tobj_id,$id,$spec_view_type,$filters);
  215. $test_spec = getTestSpecFromNode($db,$tcase_mgr,$linked_items,$tobj_id,$id,$spec_view_type,$pfFilters);
  216. $platforms = getPlatforms($db,$tproject_id,$testplan_id);
  217. $idx = 0;
  218. $a_tcid = array();
  219. $a_tsuite_idx = array();
  220. if(count($test_spec))
  221. {
  222. $cfg = array('node_types' => $hash_id_descr, 'write_status' => $write_status,
  223. 'is_uncovered_view_type' => $is_uncovered_view_type);
  224. list($a_tcid,$a_tsuite_idx,$tsuite_tcqty,$out) = buildSkeleton($id,$name,$cfg,$test_spec,$platforms);
  225. }
  226. // This code has been replace (see below on Remove empty branches)
  227. // Once we have created array with testsuite and children testsuites
  228. // we are trying to remove nodes that has 0 test case count.
  229. // May be this can be done (as noted by schlundus during performance
  230. // analisys done on october 2008) in a better way, or better can be absolutely avoided.
  231. //
  232. // This process is needed to prune whole branches that are empty
  233. // Need to look for every call in TL and understand if this can be removed
  234. //
  235. if(!is_null($map_node_tccount))
  236. {
  237. foreach($out as $key => $elem)
  238. {
  239. if(isset($map_node_tccount[$elem['testsuite']['id']]) &&
  240. $map_node_tccount[$elem['testsuite']['id']]['testcount'] == 0)
  241. {
  242. // why not unset ?
  243. $out[$key]=null;
  244. }
  245. }
  246. }
  247. // Collect information related to linked testcase versions
  248. if(!is_null($out) && count($out) > 0 && !is_null($out[0]) && count($a_tcid))
  249. {
  250. $tcaseSet = $tcase_mgr->get_by_id($a_tcid,testcase::ALL_VERSIONS);
  251. $result = addLinkedVersionsInfo($tcaseSet,$a_tsuite_idx,$out,$linked_items);
  252. }
  253. // Try to prune empty test suites, to reduce memory usage and to remove elements
  254. // that do not need to be displayed on user interface.
  255. if( count($result['spec_view']) > 0)
  256. {
  257. removeEmptyTestSuites($result['spec_view'],$tcase_mgr->tree_manager,
  258. ($my['options']['prune_unlinked_tcversions'] && $is_tplan_view_type),$hash_descr_id);
  259. }
  260. // Remove empty branches
  261. // Loop to compute test case qty ($tsuite_tcqty) on every level and prune test suite branchs that are empty
  262. if( count($result['spec_view']) > 0)
  263. {
  264. removeEmptyBranches($result['spec_view'],$tsuite_tcqty);
  265. }
  266. /** @TODO: maybe we can integrate this into already present loops above? */
  267. // This is not right condition for identifing an empty test suite for the porpouse
  268. // of gen_spec_view(), because for following structure
  269. // TS1
  270. // \--- TS2
  271. // \--TC1
  272. // \--TC2
  273. //
  274. // \--- TS3
  275. // \-- TXX
  276. //
  277. // When we are displaying a Test Specification we want to see previous structure
  278. // But if we apply this criteria for empty test suite, TS1 results empty and will
  279. // be removed -> WRONG
  280. //
  281. // Need to understand when this feature will be needed and then reimplement
  282. //
  283. // if ($prune_empty_tsuites)
  284. // {
  285. // foreach($result['spec_view'] as $key => $value)
  286. // {
  287. // if(is_null($value) || !isset($value['testcases']) || !count($value['testcases']))
  288. // unset($result['spec_view'][$key]);
  289. // }
  290. // }
  291. // #1650 We want to manage custom fields when user is doing test case execution assigment
  292. if( count($result['spec_view']) > 0 && $my['options']['add_custom_fields'])
  293. {
  294. addCustomFieldsToView($result['spec_view'],$tproject_id,$tcase_mgr);
  295. }
  296. // --------------------------------------------------------------------------------------------
  297. unset($tcase_mgr);
  298. // with array_values() we reindex array to avoid "holes"
  299. $result['spec_view']= array_values($result['spec_view']);
  300. return $result;
  301. }
  302. /**
  303. * get linked versions filtered by Keyword ID
  304. * Filter is done ONLY on attributes THAT ARE COMMON to ALL test case versions,
  305. * because (till now) while adding/removing test cases user works on Test Spec Tree
  306. * and filter applied to this tree acts on:
  307. *
  308. * 1. attributes COMMON to all versions
  309. * 2. attributes present ON LAST ACTIVE version.
  310. *
  311. * But do no make considerations regarding versions linked to test plan
  312. * DEV NOTE: may be this has to be changed in future ?
  313. *
  314. * @param ref $argsObj: stdClass object with information about filters
  315. * @param ref $tplanMgr: test plan manager object
  316. * @param ref $tcaseMgr: test case manager object
  317. *
  318. *
  319. * @internal Revisions:
  320. *
  321. * 20100721 - asimon - BUGID 3046, added $options
  322. * 20080919 - franciscom - BUGID 2716
  323. *
  324. */
  325. function getFilteredLinkedVersions(&$argsObj, &$tplanMgr, &$tcaseMgr, $options = null)
  326. {
  327. $doFilterByKeyword=(!is_null($argsObj->keyword_id) && $argsObj->keyword_id > 0) ? true : false;
  328. // Multiple step algoritm to apply keyword filter on type=AND
  329. // get_linked_tcversions filters by keyword ALWAYS in OR mode.
  330. //
  331. // BUGID 2797 - filter by test case execution type
  332. // $filters = array('keyword_id' => $argsObj->keyword_id, 'exec_type' => $argsObj->executionType);
  333. $filters = array('keyword_id' => $argsObj->keyword_id);
  334. $options = array('output' => 'mapOfArray') + (array)$options;
  335. $tplan_tcases = $tplanMgr->get_linked_tcversions($argsObj->tplan_id, $filters, $options);
  336. // BUGID 2716
  337. if( !is_null($tplan_tcases) && $doFilterByKeyword && $argsObj->keywordsFilterType == 'AND')
  338. {
  339. $filteredSet=$tcaseMgr->filterByKeyword(array_keys($tplan_tcases),
  340. $argsObj->keyword_id,$argsObj->keywordsFilterType);
  341. $testCaseSet=array_keys($filteredSet);
  342. $filters = array('tcase_id' => $testCaseSet);
  343. $tplan_tcases = $tplanMgr->get_linked_tcversions($argsObj->tplan_id, $filters, $options);
  344. }
  345. return $tplan_tcases;
  346. }
  347. /**
  348. *
  349. * @internal revisions:
  350. * 20100721 - asimon - BUGID 3406 - added $options for new user assignments per build
  351. * 20100218 - asimon - BUGID 3026 - added parameter $testcaseFilter to include functionality
  352. * previously used on tc_exec_assignment.php
  353. * to show only testcases present in filter argument
  354. *
  355. */
  356. function keywordFilteredSpecView(&$dbHandler, &$argsObj, $keywordsFilter, &$tplanMgr, &$tcaseMgr,
  357. $testcaseFilter = null, $options = null)
  358. {
  359. $tsuiteMgr = new testsuite($dbHandler);
  360. $tprojectMgr = new testproject($dbHandler);
  361. $tsuite_data = $tsuiteMgr->get_by_id($argsObj->id);
  362. $filterAssignedTo = property_exists($argsObj,'filter_assigned_to') ? $argsObj->filter_assigned_to : null;
  363. // 3406
  364. // $ua_build = !is_null($options) && isset($options['user_assignments_per_build']) ?
  365. // $options['user_assignments_per_build'] : null;
  366. // @TODO - 20081019
  367. // Really understand differences between:
  368. // $argsObj->keyword_id and $keywordsFilter
  369. // BUGID 1041
  370. $filters = array('keyword_id' => $argsObj->keyword_id, 'assigned_to' => $filterAssignedTo);
  371. // 20100715 - asimon - why the double writing to $tplan_linked_tcversions?
  372. // will be overwritten again two lines below
  373. // $tplan_linked_tcversions = $tplanMgr->get_linked_tcversions($argsObj->tplan_id, $filters, $options);
  374. // This does filter on keywords ALWAYS in OR mode.
  375. // 3406: added $options
  376. $tplan_linked_tcversions = getFilteredLinkedVersions($argsObj, $tplanMgr, $tcaseMgr, $options);
  377. // With this pieces we implement the AND type of keyword filter.
  378. $testCaseSet = null;
  379. if(!is_null($keywordsFilter) && !is_null($keywordsFilter->items))
  380. {
  381. $keywordsTestCases = $tprojectMgr->get_keywords_tcases($argsObj->tproject_id,
  382. $keywordsFilter->items,$keywordsFilter->type);
  383. $testCaseSet = array_keys($keywordsTestCases);
  384. }
  385. // BUGID 3026 - added $testcaseFilter
  386. if (!is_null($testCaseSet) && !is_null($testcaseFilter)) {
  387. $testCaseSet = array_intersect($testCaseSet, array($testcaseFilter));
  388. } else if (is_null($testCaseSet) && !is_null($testcaseFilter)) {
  389. $testCaseSet = $testcaseFilter;
  390. }
  391. // now get values as keys
  392. // 20100722 - asimon - additional check here because of warning from array_combine when $testCaseSet is null
  393. //$testCaseSet = array_combine($testCaseSet, $testCaseSet);
  394. $testCaseSet = !is_null($testCaseSet) ? array_combine($testCaseSet, $testCaseSet) : null;
  395. // function gen_spec_view(&$db,$spec_view_type='testproject',$tobj_id,$id,$name,&$linked_items,
  396. // $map_node_tccount,$filters=null, $options = null,$tproject_id = null)
  397. //
  398. // 3406
  399. $options = array('write_button_only_if_linked' => 1, 'prune_unlinked_tcversions' => 1)
  400. + (array)$options;
  401. $filters = array('keywords' => $argsObj->keyword_id, 'testcases' => $testCaseSet);
  402. $out = gen_spec_view($dbHandler, 'testplan', $argsObj->tplan_id, $argsObj->id, $tsuite_data['name'],
  403. $tplan_linked_tcversions, null, $filters, $options);
  404. return $out;
  405. }
  406. /**
  407. * get Test Specification data within a Node
  408. *
  409. * using nodeId (that normally is a test suite id) as starting point
  410. * will return subtree that start at nodeId.
  411. * If filters are given, the subtree returned is filtered.
  412. *
  413. * Important Notice regaring keyword filtering
  414. * Keyword filter logic inside this function seems to work ONLY on OR mode.
  415. * Then how the AND mode is implemented ?
  416. * Filter for test case id is used, and the test case set has been generated
  417. * applying AND or OR logic (following user's choice).
  418. * Then seems that logic regarding keywords here, may be can be removed
  419. *
  420. * @param integer $masterContainerId can be a Test Project Id, or a Test Plan id.
  421. * is used only if keyword id filter has been specified
  422. * to get all keyword defined on masterContainer.
  423. *
  424. * @param integer $nodeId node that will be root of the view we want to build.
  425. *
  426. * @param string $specViewType: type of view requested
  427. *
  428. * @param array $filters
  429. * filters['keyword_id']: array of keywords
  430. *
  431. *
  432. * @return array map with view (test cases subtree)
  433. *
  434. * @internal revisions
  435. * 20100417 - franciscom - BUGID 2498 - added logic to filter by importance (defined on test case spec)
  436. * 20100411 - franciscom - added logic to filter by execution type
  437. */
  438. function getTestSpecFromNode(&$dbHandler,&$tcaseMgr,&$linkedItems,$masterContainerId,$nodeId,$specViewType,$filters)
  439. {
  440. $applyFilters = false;
  441. $testCaseSet = null;
  442. $tck_map = null;
  443. $tobj_mgr = new testproject($dbHandler);
  444. $test_spec = $tobj_mgr->get_subtree($nodeId);
  445. $key2loop = null;
  446. $useAllowed = false;
  447. // 20100411 - BUGID 2797 - filter by test case execution type
  448. $useFilter=array('keyword_id' => false, 'tcase_id' => false, 'exec_type' => false);
  449. if(($useFilter['keyword_id']=$filters['keyword_id'][0] > 0))
  450. {
  451. $applyFilters = true;
  452. switch ($specViewType)
  453. {
  454. case 'testplan':
  455. $tobj_mgr = new testplan($dbHandler);
  456. break;
  457. }
  458. $tck_map = $tobj_mgr->get_keywords_tcases($masterContainerId,$filters['keyword_id']);
  459. }
  460. if( ($useFilter['tcase_id']=!is_null($filters['tcase_id']) ))
  461. {
  462. $applyFilters = true;
  463. $testCaseSet = is_array($filters['tcase_id']) ? $filters['tcase_id'] : array($filters['tcase_id']);
  464. }
  465. if( ($useFilter['execution_type'] = !is_null($filters['execution_type']) ))
  466. {
  467. $applyFilters = true;
  468. }
  469. // BUGID
  470. if( ($useFilter['importance'] = !is_null($filters['importance']) ))
  471. {
  472. $applyFilters = true;
  473. }
  474. if( $applyFilters )
  475. {
  476. $key2loop = array_keys($test_spec);
  477. // first step: generate list of TEST CASE NODES
  478. $itemSet = null ;
  479. foreach($key2loop as $key)
  480. {
  481. if( ($test_spec[$key]['node_type_id'] == $filters['tcase_node_type_id']) )
  482. {
  483. $itemSet[$test_spec[$key]['id']] = $key;
  484. }
  485. }
  486. $itemKeys = $itemSet;
  487. foreach($itemKeys as $key => $tspecKey)
  488. {
  489. if( ($useFilter['keyword_id'] && !isset($tck_map[$test_spec[$tspecKey]['id']]) ) ||
  490. ($useFilter['tcase_id'] && !in_array($test_spec[$tspecKey]['id'],$testCaseSet))
  491. )
  492. {
  493. $test_spec[$tspecKey]=null;
  494. unset($itemSet[$key]);
  495. }
  496. }
  497. if( count($itemSet) > 0 && ($useFilter['execution_type'] || $useFilter['importance']) )
  498. {
  499. $targetSet = array_keys($itemSet);
  500. $options = ($specViewType == 'testPlanLinking') ? array( 'access_key' => 'testcase_id') : null;
  501. $tcversionSet = $tcaseMgr->get_last_active_version($targetSet,$options);
  502. switch($specViewType)
  503. {
  504. case 'testPlanLinking':
  505. // We need to analise linked items and spec
  506. foreach($targetSet as $idx => $key)
  507. {
  508. $targetTestCase = $tcversionSet[$key]['testcase_id'];
  509. if( isset($linkedItems[$targetTestCase]) )
  510. {
  511. $item = current($linkedItems[$targetTestCase]);
  512. }
  513. else
  514. {
  515. $item = null;
  516. if( isset($test_spec[$itemSet[$targetTestCase]]) )
  517. {
  518. $item = $tcversionSet[$targetTestCase];
  519. }
  520. }
  521. if( !is_null($item) )
  522. {
  523. if( $useFilter['exec_type'] && ($item['execution_type'] != $filters['exec_type']) ||
  524. $useFilter['importance'] && ($item['importance'] != $filters['importance']) )
  525. {
  526. $tspecKey = $itemSet[$targetTestCase];
  527. $test_spec[$tspecKey]=null;
  528. }
  529. }
  530. }
  531. break;
  532. default:
  533. $tcvidSet = array_keys($tcversionSet);
  534. // $options = array('access_key' => 'testcase_id');
  535. $options = null;
  536. // $allowedSet = $tcaseMgr->filter_tcversions_by_exec_type($tcvidSet,$filters['exec_type'],$options);
  537. $allowedSet = $tcaseMgr->filter_tcversions_by_exec_type($tcvidSet,$filters,$options);
  538. if( !is_null($allowedSet) && count($allowedSet) > 0 )
  539. {
  540. $useAllowed = true;
  541. foreach($allowedSet as $key => $value)
  542. {
  543. $tspecKey = $itemSet[$value['testcase_id']];
  544. $test_spec[$tspecKey]['version']=$value['version'];
  545. }
  546. reset($allowedSet);
  547. }
  548. $setToRemove = array_diff_key($tcversionSet,$allowedSet);
  549. if( !is_null($setToRemove) && count($setToRemove) > 0 )
  550. {
  551. foreach($setToRemove as $key => $value)
  552. {
  553. $tspecKey = $itemSet[$value['testcase_id']];
  554. $test_spec[$tspecKey]=null;
  555. }
  556. }
  557. break;
  558. } // end switch
  559. }
  560. } // if apply filters
  561. unset($tobj_mgr);
  562. return $test_spec;
  563. }
  564. /**
  565. * remove empty Test Suites
  566. *
  567. * @param array $testSuiteSet reference to set to analyse and clean.
  568. * @param object $treeMgr reference to object
  569. * @param TBD $pruneUnlinkedTcversions useful when working on test plans
  570. * @param TBD $nodeTypes hash key: node type description, value: code
  571. */
  572. function removeEmptyTestSuites(&$testSuiteSet,&$treeMgr,$pruneUnlinkedTcversions,$nodeTypes)
  573. {
  574. foreach($testSuiteSet as $key => $value)
  575. {
  576. // We will remove test suites that meet the empty conditions:
  577. // - do not contain other test suites OR
  578. // - do not contain test cases
  579. if( is_null($value) )
  580. {
  581. unset($testSuiteSet[$key]);
  582. }
  583. else if ($pruneUnlinkedTcversions &&
  584. (isset($value['testcase_qty']) && $value['testcase_qty'] > 0) )
  585. {
  586. // only linked tcversion must be returned, but this analisys must be done
  587. // for test suites that has test cases.
  588. if( isset($value['linked_testcase_qty']) && $value['linked_testcase_qty']== 0)
  589. {
  590. unset($testSuiteSet[$key]);
  591. }
  592. else
  593. {
  594. // Only if test suite has children test cases we need to understand
  595. // if they are linked or not
  596. if( isset($value['testcases']) && count($value['testcases']) > 0 )
  597. {
  598. foreach($value['testcases'] as $skey => $svalue)
  599. {
  600. if( $svalue['linked_version_id'] == 0)
  601. {
  602. unset($testSuiteSet[$key]['testcases'][$skey]);
  603. }
  604. }
  605. }
  606. } // is_null($value)
  607. }
  608. else
  609. {
  610. // list of children test suites if useful on smarty template, in order
  611. // to draw nested div.
  612. $tsuite_id=$value['testsuite']['id'];
  613. $testSuiteSet[$key]['children_testsuites']=
  614. $treeMgr->get_subtree_list($tsuite_id,$nodeTypes['testsuite']);
  615. if( $value['testcase_qty'] == 0 && $testSuiteSet[$key]['children_testsuites']=='' )
  616. {
  617. unset($testSuiteSet[$key]);
  618. }
  619. }
  620. }
  621. }
  622. /**
  623. *
  624. *
  625. */
  626. function removeEmptyBranches(&$testSuiteSet,&$tsuiteTestCaseQty)
  627. {
  628. foreach($testSuiteSet as $key => $elem)
  629. {
  630. $tsuite_id=$elem['testsuite']['id'];
  631. if( !isset($tsuiteTestCaseQty[$tsuite_id]) )
  632. {
  633. $tsuiteTestCaseQty[$tsuite_id]=0;
  634. }
  635. if( isset($elem['children_testsuites']) && $elem['children_testsuites'] != '' )
  636. {
  637. $children=explode(',',$elem['children_testsuites']);
  638. foreach($children as $access_id)
  639. {
  640. if( isset($tsuiteTestCaseQty[$access_id]) )
  641. {
  642. $tsuiteTestCaseQty[$tsuite_id] += $tsuiteTestCaseQty[$access_id];
  643. }
  644. }
  645. }
  646. if( $tsuiteTestCaseQty[$tsuite_id]== 0 )
  647. {
  648. unset($testSuiteSet[$key]);
  649. }
  650. }
  651. } // function end
  652. /**
  653. * @param array &$testSuiteSet: changes will be done to this array
  654. * to add custom fields info.
  655. * Custom field info will be indexed by platform id
  656. *
  657. * @param integer $tprojectId
  658. * @param object &$tcaseMgr reference to testCase class instance
  659. *
  660. *
  661. * @internal revisions
  662. * 20100119 - franciscom - start fixing missing platform refactoring
  663. *
  664. */
  665. function addCustomFieldsToView(&$testSuiteSet,$tprojectId,&$tcaseMgr)
  666. {
  667. // Important:
  668. // testplan_tcversions.id value, that is used to link to manage custom fields that are used
  669. // during testplan_design is present on key 'feature_id' (only is linked_version_id != 0)
  670. foreach($testSuiteSet as $key => $value)
  671. {
  672. if( !is_null($value) )
  673. {
  674. if( isset($value['testcases']) && count($value['testcases']) > 0 )
  675. {
  676. foreach($value['testcases'] as $skey => $svalue)
  677. {
  678. if( ($linked_version_id=$svalue['linked_version_id']) > 0 )
  679. {
  680. $platformSet = array_keys($svalue['feature_id']);
  681. foreach($platformSet as $platform_id)
  682. {
  683. $testSuiteSet[$key]['testcases'][$skey]['custom_fields'][$platform_id]='';
  684. if( $linked_version_id != 0 )
  685. {
  686. $cf_name_suffix = "_" . $svalue['feature_id'][$platform_id];
  687. $cf_map = $tcaseMgr->html_table_of_custom_field_inputs($linked_version_id,null,'testplan_design',
  688. $cf_name_suffix,$svalue['feature_id'][$platform_id],
  689. null,$tprojectId);
  690. $testSuiteSet[$key]['testcases'][$skey]['custom_fields'][$platform_id] = $cf_map;
  691. }
  692. }
  693. }
  694. }
  695. }
  696. } // is_null($value)
  697. }
  698. } // function end
  699. /**
  700. *
  701. *
  702. */
  703. function buildSkeleton($id,$name,$config,&$test_spec,&$platforms)
  704. {
  705. $parent_idx=-1;
  706. $pivot_tsuite = $test_spec[0];
  707. $level = array();
  708. $tcase_memory = null;
  709. $node_types = $config['node_types'];
  710. $write_status = $config['write_status'];
  711. $is_uncovered_view_type = $config['is_uncovered_view_type'];
  712. $out=array();
  713. $idx = 0;
  714. $a_tcid = array();
  715. $a_tsuite_idx = array();
  716. $hash_id_pos[$id] = $idx;
  717. $out[$idx]['testsuite'] = array('id' => $id, 'name' => $name);
  718. $out[$idx]['testcases'] = array();
  719. $out[$idx]['write_buttons'] = 'no';
  720. $out[$idx]['testcase_qty'] = 0;
  721. $out[$idx]['level'] = 1;
  722. $out[$idx]['linked_testcase_qty'] = 0;
  723. $out[$idx]['linked_ts'] = null;
  724. $out[$idx]['linked_by'] = 0;
  725. $out[$idx]['priority'] = 0;
  726. $the_level = $out[0]['level']+1;
  727. $idx++;
  728. $tsuite_tcqty=array($id => 0);
  729. $parent_idx=-1;
  730. foreach ($test_spec as $current)
  731. {
  732. if(is_null($current))
  733. {
  734. continue;
  735. }
  736. // In some situations during processing of testcase, a change of parent can
  737. // exists, then we need to update $tsuite_tcqty
  738. if($node_types[$current['node_type_id']] == "testcase")
  739. {
  740. $tc_id = $current['id'];
  741. $parent_idx = $hash_id_pos[$current['parent_id']];
  742. $a_tsuite_idx[$tc_id] = $parent_idx;
  743. $out[$parent_idx]['testcases'][$tc_id] = array('id' => $tc_id,'name' => $current['name']);
  744. // Reference to make code reading more human friendly
  745. $outRef = &$out[$parent_idx]['testcases'][$tc_id];
  746. if($is_uncovered_view_type)
  747. {
  748. // @TODO understand impacts of platforms
  749. $outRef['external_id'] = $linked_items[$tc_id]['external_id'];
  750. }
  751. else
  752. {
  753. $out[$parent_idx]['write_buttons'] = $write_status;
  754. $out[$parent_idx]['linked_testcase_qty'] = 0;
  755. $outRef['tcversions'] = array();
  756. $outRef['tcversions_active_status'] = array();
  757. // 20080811 - franciscom - BUGID 1650 (REQ)
  758. $outRef['tcversions_execution_type'] = array();
  759. $outRef['tcversions_qty'] = 0;
  760. $outRef['linked_version_id'] = 0;
  761. $outRef['executed'] = null; // 'no';
  762. // useful for tc_exec_assignment.php
  763. $outRef['user_id'] = null; //0;
  764. $outRef['feature_id'] = null; //0;
  765. $outRef['linked_by'] = null; //0;
  766. $outRef['linked_ts'] = null;
  767. $outRef['priority'] = 0;
  768. $outRef['platforms'] = $platforms;
  769. // $outRef['importance'] = 0;
  770. }
  771. $out[$parent_idx]['testcase_qty']++;
  772. $a_tcid[] = $current['id'];
  773. // This piece is needed initialize in right way $tsuite_tcqty
  774. // in this kind of situation, for SubSuite2
  775. //
  776. // Tsuite 1
  777. // |__ SubSuite1
  778. // | |__TCX1
  779. // | |__TCX2
  780. // |
  781. // |__ SubSuite2
  782. // | |__TCY1
  783. // | |__TCY2
  784. // |
  785. // |__ TCZ1
  786. //
  787. //
  788. if( $tcase_memory['parent_id'] != $current['parent_id'] )
  789. {
  790. if( !is_null($tcase_memory) )
  791. {
  792. $pidx = $hash_id_pos[$tcase_memory['parent_id']];
  793. $xdx=$out[$pidx]['testsuite']['id'];
  794. $tsuite_tcqty[$xdx]=$out[$pidx]['testcase_qty'];
  795. }
  796. $tcase_memory=$current;
  797. }
  798. }
  799. else
  800. {
  801. // This node is a Test Suite
  802. if($parent_idx >= 0)
  803. {
  804. $xdx=$out[$parent_idx]['testsuite']['id'];
  805. $tsuite_tcqty[$xdx]=$out[$parent_idx]['testcase_qty'];
  806. }
  807. if($pivot_tsuite['parent_id'] != $current['parent_id'])
  808. {
  809. if ($pivot_tsuite['id'] == $current['parent_id'])
  810. {
  811. $the_level++;
  812. $level[$current['parent_id']] = $the_level;
  813. }
  814. else
  815. $the_level = $level[$current['parent_id']];
  816. }
  817. $out[$idx]['testsuite']=array('id' => $current['id'], 'name' => $current['name']);
  818. $out[$idx]['testcases'] = array();
  819. $out[$idx]['testcase_qty'] = 0;
  820. $out[$idx]['linked_testcase_qty'] = 0;
  821. $out[$idx]['level'] = $the_level;
  822. $out[$idx]['write_buttons'] = 'no';
  823. $hash_id_pos[$current['id']] = $idx;
  824. $idx++;
  825. // update pivot.
  826. $level[$current['parent_id']] = $the_level;
  827. $pivot_tsuite = $current;
  828. }
  829. } // foreach
  830. // Update after finished loop
  831. if($parent_idx >= 0)
  832. {
  833. $xdx=$out[$parent_idx]['testsuite']['id'];
  834. $tsuite_tcqty[$xdx]=$out[$parent_idx]['testcase_qty'];
  835. }
  836. unset($tcase_memory);
  837. $tsuite_tcqty[$id] = $out[$hash_id_pos[$id]]['testcase_qty'];
  838. return array($a_tcid,$a_tsuite_idx,$tsuite_tcqty,$out);
  839. }
  840. /**
  841. *
  842. *
  843. * @internal revisions:
  844. * 20100726 - asimon - BUGID 3628
  845. */
  846. function addLinkedVersionsInfo($testCaseSet,$a_tsuite_idx,&$out,&$linked_items)
  847. {
  848. $optionalIntegerFields = array('user_id', 'feature_id','linked_by');
  849. $result = array('spec_view'=>array(), 'num_tc' => 0, 'has_linked_items' => 0);
  850. $pivot_id=-1;
  851. foreach($testCaseSet as $the_k => $testCase)
  852. {
  853. $tc_id = $testCase['testcase_id'];
  854. // Needed when having multiple platforms
  855. if($pivot_id != $tc_id )
  856. {
  857. $pivot_id=$tc_id;
  858. $result['num_tc']++;
  859. }
  860. $parent_idx = $a_tsuite_idx[$tc_id];
  861. // Reference to make code reading more human friendly
  862. $outRef = &$out[$parent_idx]['testcases'][$tc_id];
  863. if($testCase['active'] == 1 && !is_null($out[$parent_idx]) )
  864. {
  865. if( !isset($outRef['execution_order']) )
  866. {
  867. // Doing this I will set order for test cases that still are not linked.
  868. // But Because I loop over all version (linked and not) if I always write,
  869. // will overwrite right execution order of linked tcversion.
  870. //
  871. // N.B.:
  872. // As suggested by Martin Havlat order will be set to external_id * 10
  873. $outRef['execution_order'] = $testCase['node_order']*10;
  874. }
  875. $outRef['tcversions'][$testCase['id']] = $testCase['version'];
  876. $outRef['tcversions_active_status'][$testCase['id']] = 1;
  877. $outRef['external_id'] = $testCase['tc_external_id'];
  878. $outRef['tcversions_execution_type'][$testCase['id']] = $testCase['execution_type'];
  879. if (!isset($outRef['tcversions_qty']))
  880. {
  881. $outRef['tcversions_qty']=0;
  882. }
  883. $outRef['tcversions_qty']++;
  884. }
  885. if(!is_null($linked_items))
  886. {
  887. foreach($linked_items as $linked_testcase)
  888. {
  889. if(($linked_testcase[0]['tc_id'] == $testCase['testcase_id']) &&
  890. ($linked_testcase[0]['tcversion_id'] == $testCase['id']) )
  891. {
  892. // This can be written only once no matter platform qty
  893. if( !isset($outRef['tcversions'][$testCase['id']]) )
  894. {
  895. $outRef['tcversions'][$testCase['id']] = $testCase['version'];
  896. $outRef['tcversions_active_status'][$testCase['id']] = 0;
  897. $outRef['external_id'] = $testCase['tc_external_id'];
  898. $outRef['tcversions_execution_type'][$testCase['id']] = $testCase['execution_type'];
  899. }
  900. $exec_order= isset($linked_testcase[0]['execution_order'])? $linked_testcase[0]['execution_order']:0;
  901. $outRef['execution_order'] = $exec_order;
  902. // 20090625 - Eloff
  903. // 20100726 - BUGID 3628 - asimon - missing [0] in condition
  904. // caused missing priority in GUI
  905. if( isset($linked_testcase[0]['priority']) )
  906. {
  907. $outRef['priority'] = priority_to_level($linked_testcase[0]['priority']);
  908. }
  909. $outRef['linked_version_id']= $testCase['id'];
  910. $out[$parent_idx]['write_buttons'] = 'yes';
  911. $out[$parent_idx]['linked_testcase_qty']++;
  912. $result['has_linked_items'] = 1;
  913. foreach($linked_testcase as $item)
  914. {
  915. if(intval($item['executed']))
  916. {
  917. $outRef['executed'][$item['platform_id']]='yes';
  918. }
  919. if( isset($item['linked_ts']))
  920. {
  921. $outRef['linked_ts'][$item['platform_id']]=$item['linked_ts'];
  922. }
  923. foreach ($optionalIntegerFields as $fieldKey )
  924. {
  925. if( isset($item[$fieldKey]))
  926. {
  927. $outRef[$fieldKey][$item['platform_id']]=intval($item[$fieldKey]);
  928. }
  929. }
  930. }
  931. break;
  932. }
  933. }
  934. }
  935. } //foreach($tcase_set
  936. if( !is_null($out[0]) )
  937. {
  938. $result['spec_view'] = $out;
  939. }
  940. return $result;
  941. }
  942. /**
  943. *
  944. *
  945. */
  946. function getPlatforms($db,$tproject_id,$testplan_id)
  947. {
  948. $platform_mgr = new tlPlatform($db, $tproject_id);
  949. if (is_null($testplan_id)) {
  950. $platforms = $platform_mgr->getAll();
  951. } else {
  952. $platforms = $platform_mgr->getLinkedToTestplan($testplan_id);
  953. }
  954. if( is_null($platforms) )
  955. {
  956. // need to create fake data for platform 0 in order
  957. // to have only simple logic
  958. $platforms = array( 'id' => 0, 'name' => '');
  959. }
  960. return $platforms;
  961. }
  962. ?>