PageRenderTime 53ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/functions/print.inc.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 1296 lines | 1088 code | 63 blank | 145 comment | 37 complexity | 6bf6d883ae009642e30dd070fc79bb06 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. * Library for documents generation
  7. *
  8. * @package TestLink
  9. * @author Martin Havlat <havlat@users.sourceforge.net>
  10. * @copyright 2007-2009, TestLink community
  11. * @version $Id: print.inc.php,v 1.106 2010/08/04 03:08:24 amkhullar Exp $
  12. * @uses printDocument.php
  13. *
  14. *
  15. * @internal
  16. *
  17. * Revisions:
  18. * 20100803 - amitkhullar - Added condition check for null req. custom fields @line 230/346
  19. * 20100723 - asimon - BUGID 3459: added platform ID to renderTestCaseForPrinting(),
  20. * renderTestSpecTreeForPrinting() and
  21. * renderTestPlanForPrinting()
  22. * 20100723 - asimon - BUGID 3451 and related: solved by changes in renderTestCaseForPrinting()
  23. * 20100326 - asimon - started refactoring and moving of requirement printing functions from
  24. * req classes to this file for generation of req spec document
  25. * like it is done for testcases (BUGID 3067)
  26. * 20100306 - contribution by romans - BUGID 0003235: Printing Out Test Report Shows
  27. * empty Column Headers for "Steps" and "Step Actions"
  28. *
  29. * 20100106 - franciscom - Multiple Test Case Steps Feature
  30. * 20100105 - franciscom - added tableColspan,firstColWidth config
  31. * 20090906 - franciscom - added contribution by Eloff:
  32. * - regarding platforms feature
  33. * - Moved toc to be outside of report content
  34. * - Changed the anchor ids
  35. *
  36. * 20090902 - franciscom - preconditions (printed only if not empty).
  37. * 20090719 - franciscom - added Test Case CF location management
  38. * added utility functions to clean up code
  39. * and have a more modular design
  40. *
  41. * 20090330 - franciscom - fixed internal bug when decoding user names
  42. * 20090410 - amkhullar - BUGID 2368
  43. * 20090330 - franciscom - renderTestSpecTreeForPrinting() -
  44. * added logic to print ALWAYS test plan custom fields
  45. * 20090329 - franciscom - renderTestCaseForPrinting() refactoring of code regarding custom fields
  46. * renderTestSuiteNodeForPrinting() - print ALWAYS custom fields
  47. * 20090326 - amkhullar - BUGID 2207 - Code to Display linked bugs to a TC in Test Report
  48. * 20090322 - amkhullar - added check box for Test Case Custom Field display on Test Plan/Report
  49. * 20090223 - havlatm - estimated execution moved to extra chapter, refactoring a few functions
  50. * 20090129 - havlatm - removed base tag from header (problems with internal links for some browsers)
  51. * 20081207 - franciscom - BUGID 1910 - changes on display of estimated execution time
  52. * added code to display CF with scope='execution'
  53. *
  54. * 20080820 - franciscom - added contribution (BUGID 1670)
  55. * Test Plan report:
  56. * Total Estimated execution time will be printed
  57. * on table of contents.
  58. * Compute of this time can be done if:
  59. * - Custom Field with Name CF_ESTIMATED_EXEC_TIME exists
  60. * - Custom Field is managed at design time
  61. * - Custom Field is assigned to Test Cases
  62. *
  63. * Important Note:
  64. * Lots of controls must be developed to avoid problems
  65. * presenting with results, when user use time with decimal part.
  66. * Example:
  67. * 14.6 minuts what does means?
  68. * a) 14 min and 6 seconds?
  69. * b) 14 min and 6% of 1 minute => 14 min 3.6 seconds ?
  70. *
  71. * Implementation at (20080820) is very simple => is user
  72. * responsibility to use good times (may be always interger values)
  73. * to avoid problems.
  74. * Another choice: TL must round individual times before doing sum.
  75. *
  76. * 20080819 - franciscom - renderTestCaseForPrinting() - removed mysql only code
  77. * 20080602 - franciscom - display testcase external id
  78. * 20080525 - havlatm - fixed missing test result
  79. * 20080505 - franciscom - renderTestCaseForPrinting() - added custom fields
  80. * 20080418 - franciscom - document_generation configuration .
  81. * removed tlCfg global coupling
  82. * 20071014 - franciscom - renderTestCaseForPrinting() added printing of test case version
  83. * 20070509 - franciscom - changes in renderTestSpecTreeForPrinting() interface
  84. *
  85. */
  86. /** uses get_bugs_for_exec() */
  87. require_once("exec.inc.php");
  88. /**
  89. * render a requirement as HTML code for printing
  90. *
  91. * @author Andreas Simon
  92. *
  93. * @param resource $db
  94. * @param array $node the node to be printed
  95. * @param array $printingOptions
  96. * @param string $tocPrefix Prefix to be printed in TOC before title of node
  97. * @param int $level
  98. * @param int $tprojectID
  99. *
  100. * @return string $output HTML Code
  101. */
  102. function renderRequirementNodeForPrinting(&$db,$node, &$printingOptions, $tocPrefix, $level, $tprojectID) {
  103. static $tableColspan;
  104. static $firstColWidth;
  105. static $labels;
  106. static $title_separator;
  107. static $req_mgr;
  108. static $tplan_mgr;
  109. static $req_cfg;
  110. static $req_spec_cfg;
  111. static $reqStatusLabels;
  112. static $reqTypeLabels;
  113. if (!$req_mgr) {
  114. $req_cfg = config_get('req_cfg');
  115. $req_spec_cfg = config_get('req_spec_cfg');
  116. $firstColWidth = '20%';
  117. $tableColspan = 2;
  118. $labels = array('requirement' => 'requirement', 'status' => 'status',
  119. 'scope' => 'scope', 'type' => 'type', 'author' => 'author',
  120. 'relations' => 'relations',
  121. 'coverage' => 'coverage',
  122. 'custom_field' => 'custom_field', 'relation_project' => 'relation_project',
  123. 'related_tcs' => 'related_tcs');
  124. $labels = init_labels($labels);
  125. $reqStatusLabels = init_labels($req_cfg->status_labels);
  126. $reqTypeLabels = init_labels($req_cfg->type_labels);
  127. $title_separator = config_get('gui_title_separator_1');
  128. $req_mgr = new requirement_mgr($db);
  129. $tplan_mgr = new testplan($db);
  130. }
  131. $arrReq = $req_mgr->get_by_id($node['id']);
  132. $req = $arrReq[0];
  133. $name = htmlspecialchars($req["req_doc_id"] . $title_separator . $req['title']);
  134. $output = "<table class=\"req\"><tr><th colspan=\"$tableColspan\">" .
  135. "<span class=\"label\">{$labels['requirement']}:</span> " . $name . "</th></tr>\n";
  136. if ($printingOptions['toc']) {
  137. $printingOptions['tocCode'] .= '<p style="padding-left: ' .
  138. (15*$level).'px;"><a href="#' . prefixToHTMLID('req'.$node['id']) . '">' .
  139. $name . '</a></p>';
  140. $output .= '<a name="' . prefixToHTMLID('req'.$node['id']) . '"></a>';
  141. }
  142. if ($printingOptions['req_author']) {
  143. $author = tlUser::getById($db,$req['author_id']);
  144. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  145. $labels['author'] . "</span></td><td> " .
  146. htmlspecialchars($author->getDisplayName()) . "</td></tr>\n";
  147. }
  148. if ($printingOptions['req_status']) {
  149. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  150. $labels['status'] . "</span></td>" .
  151. "<td>" . $reqStatusLabels[$req['status']] . "</td></tr>";
  152. }
  153. if ($printingOptions['req_type']) {
  154. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  155. $labels['type'] . "</span></td>" .
  156. "<td>" . $reqTypeLabels[$req['type']] . "</td></tr>";
  157. }
  158. if ($printingOptions['req_coverage']) {
  159. $current = count($req_mgr->get_coverage($req['id']));
  160. $expected = $req['expected_coverage'];
  161. $coverage = lang_get('not_aplicable') . " ($current/0)";
  162. if ($expected) {
  163. $percentage = round(100 / $expected * $current, 2);
  164. $coverage = "{$percentage}% ({$current}/{$expected})";
  165. }
  166. $output .= "<tr><td width=\"$firstColWidth\"><span class=\"label\">" . $labels['coverage'] . "</span></td>" .
  167. "<td>$coverage</td></tr>";
  168. }
  169. if ($printingOptions['req_scope']) {
  170. $output .= "<tr><td colspan=\"$tableColspan\"><span class=\"label\">" . $labels['scope'] .
  171. "</span><br/>" . $req['scope'] . "</td></tr>";
  172. }
  173. if ($printingOptions['req_relations']) {
  174. $relations = $req_mgr->get_relations($req['id']);
  175. if ($relations['num_relations']) {
  176. $output .= "<tr><td width=\"$firstColWidth\"><span class=\"label\">" . $labels['relations'] . "</span></td>" .
  177. "<td>";
  178. foreach ($relations['relations'] as $rel) {
  179. $output .= "{$rel['type_localized']}: <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
  180. htmlspecialchars($rel['related_req']['req_doc_id']) . $title_separator .
  181. htmlspecialchars($rel['related_req']['title']) . "</br>" .
  182. "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{$labels['status']}: " .
  183. "{$reqStatusLabels[$rel['related_req']['status']]} <br/>";
  184. if ($req_cfg->relations->interproject_linking) {
  185. $output .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{$labels['relation_project']}: " .
  186. htmlspecialchars($rel['related_req']['testproject_name']) . " <br/>";
  187. }
  188. }
  189. $output .= "</td></tr>";
  190. }
  191. }
  192. if ($printingOptions['req_linked_tcs']) {
  193. $req_coverage = $req_mgr->get_coverage($req['id']);
  194. if (count($req_coverage)) {
  195. $output .= "<tr><td width=\"$firstColWidth\"><span class=\"label\">" . $labels['related_tcs'] . "</span></td>" .
  196. "<td>";
  197. foreach ($req_coverage as $tc) {
  198. $output .= htmlentities($tc['tc_external_id'] . $title_separator .
  199. $tc['name']) . "<br/>";
  200. }
  201. $output .= "</td></tr>";
  202. }
  203. }
  204. if ($printingOptions['req_cf'])
  205. {
  206. $linked_cf = $req_mgr->get_linked_cfields($req['id']);
  207. if ($linked_cf)
  208. {
  209. foreach ($linked_cf as $key => $cf)
  210. {
  211. $cflabel = htmlspecialchars($cf['label']);
  212. $value = htmlspecialchars($cf['value']);
  213. $output .= "<tr><td width=\"$firstColWidth\"><span class=\"label\">" .
  214. $cflabel . "</span></td>" .
  215. "<td>$value</td></tr>";
  216. }
  217. }
  218. }
  219. $output .= "</table><br/>";
  220. return $output;
  221. }
  222. /**
  223. * render a requirement specification node as HTML code for printing
  224. *
  225. * @author Andreas Simon
  226. *
  227. * @param resource $db
  228. * @param array $node the node to be printed
  229. * @param array $printingOptions
  230. * @param string $tocPrefix Prefix to be printed in TOC before title of node
  231. * @param int $level
  232. * @param int $tprojectID
  233. *
  234. * @return string $output HTML Code
  235. */
  236. function renderReqSpecNodeForPrinting(&$db, &$node, &$printingOptions, $tocPrefix, $level, $tprojectID) {
  237. static $tableColspan;
  238. static $firstColWidth;
  239. static $labels;
  240. static $title_separator;
  241. static $req_spec_mgr;
  242. static $tplan_mgr;
  243. static $req_spec_cfg;
  244. static $reqSpecTypeLabels;
  245. if (!$req_spec_mgr) {
  246. $req_spec_cfg = config_get('req_spec_cfg');
  247. $firstColWidth = '20%';
  248. $tableColspan = 2;
  249. $labels = array('requirements_spec' => 'requirements_spec',
  250. 'scope' => 'scope', 'type' => 'type', 'author' => 'author',
  251. 'relations' => 'relations', 'overwritten_count' => 'req_total',
  252. 'coverage' => 'coverage',
  253. 'custom_field' => 'custom_field', 'not_aplicable' => 'not_aplicable');
  254. $labels = init_labels($labels);
  255. $reqSpecTypeLabels = init_labels($req_spec_cfg->type_labels);
  256. $title_separator = config_get('gui_title_separator_1');
  257. $req_spec_mgr = new requirement_spec_mgr($db);
  258. $tplan_mgr = new testplan($db);
  259. }
  260. $spec = $req_spec_mgr->get_by_id($node['id']);
  261. $name = htmlspecialchars($spec['doc_id'] . $title_separator . $spec['title']);
  262. $docHeadingNumbering = '';
  263. if ($printingOptions['headerNumbering']) {
  264. $docHeadingNumbering = "$tocPrefix. ";
  265. }
  266. $output = "<table class=\"req_spec\"><tr><th colspan=\"$tableColspan\">" .
  267. "<span class=\"label\">{$docHeadingNumbering}{$labels['requirements_spec']}:</span> " .
  268. $name . "</th></tr>\n";
  269. if ($printingOptions['toc'])
  270. {
  271. $spacing = ($level == 2) ? "<br>" : "";
  272. $printingOptions['tocCode'] .= $spacing.'<b><p style="padding-left: '.(10*$level).'px;">' .
  273. '<a href="#' . prefixToHTMLID($tocPrefix) . '">' . $docHeadingNumbering . $name . "</a></p></b>\n";
  274. $output .= "<a name='". prefixToHTMLID($tocPrefix) . "'></a>\n";
  275. }
  276. if ($printingOptions['req_spec_author']) {
  277. // get author name for node
  278. $author = tlUser::getById($db, $spec['author_id']);
  279. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  280. $labels['author'] . "</span></td><td> " .
  281. htmlspecialchars($author->getDisplayName()) . "</td></tr>\n";
  282. }
  283. if ($printingOptions['req_spec_type']) {
  284. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  285. $labels['type'] . "</span></td>" .
  286. "<td>" . $reqSpecTypeLabels[$spec['type']] . "</td></tr>";
  287. }
  288. if ($printingOptions['req_spec_overwritten_count_reqs']) {
  289. $current = $req_spec_mgr->get_requirements_count($spec['id']);
  290. $expected = $spec['total_req'];
  291. $coverage = $labels['not_aplicable'] . " ($current/0)";
  292. if ($expected) {
  293. $percentage = round(100 / $expected * $current, 2);
  294. $coverage = "{$percentage}% ({$current}/{$expected})";
  295. }
  296. $output .= '<tr><td width="' . $firstColWidth . '"><span class="label">' .
  297. $labels['overwritten_count'] . " (" . $labels['coverage'] . ")</span></td>" .
  298. "<td>" . $coverage . "</td></tr>";
  299. }
  300. if ($printingOptions['req_spec_scope']) {
  301. $output .= "<tr><td colspan=\"$tableColspan\"><span class=\"label\">" . $labels['scope'] .
  302. "</span><br/>" . $spec['scope'] . "</td></tr>";
  303. }
  304. if ($printingOptions['req_spec_cf']) {
  305. $linked_cf = $req_spec_mgr->get_linked_cfields($spec['id']);
  306. if ($linked_cf){
  307. foreach ($linked_cf as $key => $cf) {
  308. $cflabel = htmlspecialchars($cf['label']);
  309. $value = htmlspecialchars($cf['value']);
  310. $output .= "<tr><td width=\"$firstColWidth\"><span class=\"label\">" .
  311. $cflabel . "</span></td>" .
  312. "<td>$value</td></tr>";
  313. }
  314. }
  315. }
  316. $output .= "</table><br/>\n";
  317. return $output;
  318. }
  319. /**
  320. * render a complete tree, consisting of mixed requirement and req spec nodes,
  321. * as HTML code for printing
  322. *
  323. * @author Andreas Simon
  324. *
  325. * @param resource $db
  326. * @param array $node the node to be printed
  327. * @param array $printingOptions
  328. * @param string $tocPrefix Prefix to be printed in TOC before title of each node
  329. * @param int $level
  330. * @param int $tprojectID
  331. * @param int $user_id ID of user which shall be printed as author of the document
  332. *
  333. * @return string $output HTML Code
  334. */
  335. function renderReqSpecTreeForPrinting(&$db, &$node, &$printingOptions,
  336. $tocPrefix, $rsCnt, $level, $user_id,
  337. $tplan_id = 0, $tprojectID = 0) {
  338. static $tree_mgr;
  339. static $map_id_descr;
  340. static $tplan_mgr;
  341. $code = null;
  342. if(!$tree_mgr)
  343. {
  344. $tplan_mgr = new testplan($db);
  345. $tree_mgr = new tree($db);
  346. $map_id_descr = $tree_mgr->node_types;
  347. }
  348. $verbose_node_type = $map_id_descr[$node['node_type_id']];
  349. switch($verbose_node_type)
  350. {
  351. case 'testproject':
  352. break;
  353. case 'requirement_spec':
  354. $tocPrefix .= (!is_null($tocPrefix) ? "." : '') . $rsCnt;
  355. $code .= renderReqSpecNodeForPrinting($db,$node,$printingOptions,
  356. $tocPrefix, $level, $tprojectID);
  357. break;
  358. case 'requirement':
  359. $tocPrefix .= (!is_null($tocPrefix) ? "." : '') . $rsCnt;
  360. $code .= renderRequirementNodeForPrinting($db, $node, $printingOptions,
  361. $tocPrefix, $level, $tprojectID);
  362. break;
  363. }
  364. if (isset($node['childNodes']) && $node['childNodes'])
  365. {
  366. $childNodes = $node['childNodes'];
  367. $rsCnt = 0;
  368. $children_qty = sizeof($childNodes);
  369. for($i = 0;$i < $children_qty ;$i++)
  370. {
  371. $current = $childNodes[$i];
  372. if(is_null($current))
  373. {
  374. continue;
  375. }
  376. if (isset($current['node_type_id']) &&
  377. $map_id_descr[$current['node_type_id']] == 'requirement_spec')
  378. {
  379. $rsCnt++;
  380. }
  381. $code .= renderReqSpecTreeForPrinting($db, $current, $printingOptions,
  382. $tocPrefix, $rsCnt, $level+1, $user_id,
  383. $tplan_id, $tprojectID);
  384. }
  385. }
  386. if ($verbose_node_type == 'testproject')
  387. {
  388. if ($printingOptions['toc'])
  389. {
  390. $code = str_replace("{{INSERT_TOC}}",$printingOptions['tocCode'],$code);
  391. }
  392. }
  393. return $code;
  394. }
  395. /**
  396. * render HTML header
  397. * Standard: HTML 4.01 trans (because is more flexible to bugs in user data)
  398. *
  399. * @param string $title
  400. * @param string $base_href Base URL
  401. *
  402. * @return string html data
  403. */
  404. function renderHTMLHeader($title,$base_href)
  405. {
  406. // BUGID 3424
  407. $themeDir = config_get('theme_dir');
  408. $docCfg = config_get('document_generator');
  409. $cssFile = $base_href . $themeDir . $docCfg->css_template;
  410. $output = "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n";
  411. $output .= "<html>\n<head>\n";
  412. $output .= '<meta http-equiv="Content-Type" content="text/html; charset=' . config_get('charset') . '">';
  413. $output .= '<title>' . htmlspecialchars($title). "</title>\n";
  414. // $output .= '<link type="text/css" rel="stylesheet" href="'. $base_href . $docCfg->css_template ."\" />\n";
  415. $output .= '<link type="text/css" rel="stylesheet" href="'. $cssFile ."\" />\n";
  416. // way to add CSS directly to the exported file (not used - test required)
  417. // $docCss = file_get_contents(TL_ABS_PATH . $docCfg->css_template);
  418. // $output .= '<style type="text/css" media="all">'."\n<!--\n".$docCss."\n-->\n</style>\n";
  419. $output .= '<style type="text/css" media="print">.notprintable { display:none;}</style>';
  420. $output .= "\n</head>\n";
  421. return $output;
  422. }
  423. /**
  424. * Generate initial page of document
  425. *
  426. * @param object $doc_info data with the next string values:
  427. * title
  428. * type_name: what does this means ???
  429. * author, tproject_name, testplan_name
  430. * @return string html
  431. * @author havlatm
  432. */
  433. function renderFirstPage($doc_info)
  434. {
  435. $docCfg = config_get('document_generator');
  436. $date_format_cfg = config_get('date_format');
  437. $output = "<body>\n<div>\n";
  438. // Print header
  439. if ($docCfg->company_name != '' )
  440. {
  441. $output .= '<div style="float:right;">' . htmlspecialchars($docCfg->company_name) ."</div>\n";
  442. }
  443. $output .= '<div>'. $doc_info->tproject_name . "</div><hr />\n";
  444. if ($docCfg->company_logo != '' )
  445. {
  446. $output .= '<p style="text-align: center;"><img alt="TestLink logo" ' .
  447. 'title="configure using $tlCfg->company->logo_image"'.
  448. ' src="' . $_SESSION['basehref'] . TL_THEME_IMG_DIR . $docCfg->company_logo . '" /></p>';
  449. }
  450. $output .= "</div>\n";
  451. $output .= '<div class="doc_title"><p>' . $doc_info->title . '</p>';
  452. $output .= '<p>'.$doc_info->type_name.'</p>';
  453. $output .= "</div>\n";
  454. // Print summary on the first page
  455. $output .= '<div class="summary">' .
  456. '<p id="prodname">'. lang_get('project') .": " . $doc_info->tproject_name . "</p>\n";
  457. $output .= '<p id="author">' . lang_get('author').": " . $doc_info->author . "</p>\n" .
  458. '<p id="printedby">' . lang_get('printed_by_TestLink_on')." ".
  459. strftime($date_format_cfg, time()) . "</p></div>\n";
  460. // Print legal notes
  461. if ($docCfg->company_copyright != '')
  462. {
  463. $output .= '<div class="pagefooter" id="copyright">' . $docCfg->company_copyright."</div>\n";
  464. }
  465. if ($docCfg->confidential_msg != '')
  466. {
  467. $output .= '<div class="pagefooter" id="confidential">' . $docCfg->confidential_msg . "</div>\n";
  468. }
  469. return $output;
  470. }
  471. /**
  472. * Generate a chapter to a document
  473. *
  474. * @param string $title
  475. * @param string $content
  476. *
  477. * @return string html
  478. * @author havlatm
  479. */
  480. function renderSimpleChapter($title, $content)
  481. {
  482. $output = '';
  483. if ($content != "")
  484. {
  485. $output .= '<h1 class="doclevel">'.$title."</h1>\n";
  486. $output .= '<div class="txtlevel">' .$content . "</div>\n <br/>";
  487. }
  488. return $output;
  489. }
  490. /*
  491. function: renderTestSpecTreeForPrinting
  492. args :
  493. returns:
  494. rev :
  495. 20100723 - asimon - BUGID 3459 - $added platform_id
  496. 20070509 - franciscom - added $tplan_id in order to refactor and
  497. add contribution BUGID
  498. */
  499. function renderTestSpecTreeForPrinting(&$db,&$node,$item_type,&$printingOptions,
  500. $tocPrefix,$tcCnt,$level,$user_id,
  501. $tplan_id = 0,$tcPrefix = null,
  502. $tprojectID = 0, $platform_id = 0)
  503. {
  504. static $tree_mgr;
  505. static $map_id_descr;
  506. static $tplan_mgr;
  507. $code = null;
  508. if(!$tree_mgr)
  509. {
  510. $tplan_mgr = new testplan($db);
  511. $tree_mgr = new tree($db);
  512. $map_id_descr = $tree_mgr->node_types;
  513. }
  514. $verbose_node_type = $map_id_descr[intval($node['node_type_id'])];
  515. switch($verbose_node_type)
  516. {
  517. case 'testproject':
  518. if($tplan_id != 0)
  519. {
  520. // 20090330 - franciscom
  521. // we are printing a test plan, get it's custom fields
  522. $cfieldFormatting=array('table_css_style' => 'class="cf"');
  523. if ($printingOptions['cfields'])
  524. {
  525. $cfields = $tplan_mgr->html_table_of_custom_field_values($tplan_id,'design',null,$cfieldFormatting);
  526. $code .= '<p>' . $cfields . '</p>';
  527. }
  528. }
  529. // platform changes - $code .= renderTOC($printingOptions);
  530. break;
  531. case 'testsuite':
  532. $tocPrefix .= (!is_null($tocPrefix) ? "." : '') . $tcCnt;
  533. $code .= renderTestSuiteNodeForPrinting($db,$node,$printingOptions,
  534. $tocPrefix,$level,$tplan_id,$tprojectID);
  535. break;
  536. case 'testcase':
  537. // 3459 - added $platform_id
  538. $code .= renderTestCaseForPrinting($db, $node, $printingOptions, $level,
  539. $tplan_id, $tcPrefix, $tprojectID, $platform_id);
  540. break;
  541. }
  542. if (isset($node['childNodes']) && $node['childNodes'])
  543. {
  544. $childNodes = $node['childNodes'];
  545. $tsCnt = 0;
  546. $children_qty = sizeof($childNodes);
  547. for($i = 0;$i < $children_qty ;$i++)
  548. {
  549. $current = $childNodes[$i];
  550. if(is_null($current))
  551. {
  552. continue;
  553. }
  554. if (isset($current['node_type_id']) &&
  555. $map_id_descr[$current['node_type_id']] == 'testsuite')
  556. {
  557. $tsCnt++;
  558. }
  559. // 3459 - added $platform_id
  560. $code .= renderTestSpecTreeForPrinting($db, $current, $item_type, $printingOptions,
  561. $tocPrefix, $tsCnt, $level+1, $user_id,
  562. $tplan_id, $tcPrefix, $tprojectID, $platform_id);
  563. }
  564. }
  565. if ($verbose_node_type == 'testproject')
  566. {
  567. if ($printingOptions['toc'])
  568. {
  569. // remove for platforms feature
  570. // $printingOptions['tocCode'] .= '</div><hr />';
  571. $code = str_replace("{{INSERT_TOC}}",$printingOptions['tocCode'],$code);
  572. }
  573. }
  574. return $code;
  575. }
  576. /**
  577. * get user name from pool (save used names in session to improve performance)
  578. *
  579. * @param integer $db DB connection identifier
  580. * @param integer $userId
  581. *
  582. * @return string readable user name
  583. * @author havlatm
  584. */
  585. function gendocGetUserName(&$db, $userId)
  586. {
  587. $authorName = null;
  588. if(isset($_SESSION['userNamePool'][$userId]))
  589. {
  590. $authorName = $_SESSION['userNamePool'][$userId];
  591. }
  592. else
  593. {
  594. $user = tlUser::getByID($db,$userId);
  595. if ($user)
  596. {
  597. $authorName = $user->getDisplayName();
  598. $authorName = htmlspecialchars($authorName);
  599. $_SESSION['userNamePool'][$userId] = $authorName;
  600. }
  601. else
  602. {
  603. $authorName = lang_get('undefined');
  604. tLog('tlUser::getByID($db,$userId) failed', 'ERROR');
  605. }
  606. }
  607. return $authorName;
  608. }
  609. /**
  610. * render Test Case content for generated documents
  611. *
  612. * @param $integer db DB connection identifier
  613. * @return string generated html code
  614. * @internal
  615. * 20100724 - asimon - BUGID 3459 - added platform ID
  616. * 20100723 - asimon - BUGID 3451 and related finally solved
  617. * 20090517 - havlatm - fixed execution layot; added tester name
  618. * 20080819 - franciscom - removed mysql only code
  619. * 20071014 - franciscom - display test case version
  620. * 20070509 - franciscom - added Contribution
  621. */
  622. function renderTestCaseForPrinting(&$db, &$node, &$printingOptions, $level, $tplan_id = 0,
  623. $prefix = null, $tprojectID = 0, $platform_id = 0)
  624. {
  625. static $req_mgr;
  626. static $tc_mgr;
  627. static $labels;
  628. static $tcase_prefix;
  629. static $userMap = array();
  630. static $cfg;
  631. static $locationFilters;
  632. static $tables = null;
  633. if (!$tables)
  634. {
  635. $tables = tlDBObject::getDBTables(array('executions','builds'));
  636. }
  637. $code = null;
  638. $tcInfo = null;
  639. $tcResultInfo = null;
  640. $tcase_pieces = null;
  641. $cfieldFormatting = array('td_css_style' => '','add_table' => false);
  642. // init static elements
  643. $id = $node['id'];
  644. if(!$cfg)
  645. {
  646. $tc_mgr = new testcase($db);
  647. list($cfg,$labels) = initRenderTestCaseCfg($tc_mgr);
  648. if(!is_null($prefix))
  649. {
  650. $tcase_prefix = $prefix;
  651. }
  652. else
  653. {
  654. list($tcase_prefix,$dummy) = $tc_mgr->getPrefix($id);
  655. }
  656. $tcase_prefix .= $cfg['testcase']->glue_character;
  657. }
  658. $versionID = isset($node['tcversion_id']) ? $node['tcversion_id'] : testcase::LATEST_VERSION;
  659. $tcInfo = $tc_mgr->get_by_id($id,$versionID);
  660. if ($tcInfo)
  661. {
  662. $tcInfo = $tcInfo[0];
  663. }
  664. $external_id = $tcase_prefix . $tcInfo['tc_external_id'];
  665. $name = htmlspecialchars($node['name']);
  666. // ----- BUGID 3451 and related ---------------------------------------
  667. // asimon: I finally found the real problem here:
  668. // $versionID was used in the following "dirty" SQL statement, but was still set to "-1"
  669. //(the value to load all tc versions) instead of a real testcase version ID.
  670. $versionID = $tcInfo['id'];
  671. // This still does not change the fact that this marked SQL statement below
  672. // should be removed and replaced by existing functions.
  673. // ----- BUGID 3451 and related ---------------------------------------
  674. $cfields = array('specScope' => null, 'execScope' => null);
  675. // get custom fields that has specification scope
  676. if ($printingOptions['cfields'])
  677. {
  678. if (!$locationFilters)
  679. $locationFilters = $tc_mgr->buildCFLocationMap();
  680. // 20090719 - franciscom - cf location
  681. foreach($locationFilters as $fkey => $fvalue)
  682. {
  683. $cfields['specScope'][$fkey] =
  684. $tc_mgr->html_table_of_custom_field_values($id,'design',$fvalue,null,$tplan_id,
  685. $tprojectID,$cfieldFormatting);
  686. }
  687. }
  688. /**
  689. * @TODO THIS IS NOT THE WAY TO DO THIS IS ABSOLUTELY WRONG AND MUST BE REFACTORED,
  690. * using existent methods - franciscom - 20090329
  691. * Need to get CF with execution scope
  692. */
  693. $exec_info = null;
  694. $bGetExecutions = false;
  695. if ($printingOptions["docType"] != DOC_TEST_SPEC)
  696. $bGetExecutions = ($printingOptions['cfields'] || $printingOptions['passfail']);
  697. if ($bGetExecutions)
  698. {
  699. $sql = " SELECT E.id AS execution_id, E.status, E.execution_ts, E.tester_id," .
  700. " E.notes, E.build_id, E.tcversion_id,E.tcversion_number,E.testplan_id," .
  701. " B.name AS build_name " .
  702. " FROM {$tables['executions']} E, {$tables['builds']} B" .
  703. " WHERE E.build_id= B.id " .
  704. " AND E.tcversion_id = {$versionID} " .
  705. " AND E.testplan_id = {$tplan_id} " .
  706. " AND E.platform_id = {$platform_id} " .
  707. " ORDER BY execution_id DESC";
  708. $exec_info = $db->get_recordset($sql,null,1);
  709. }
  710. // Added condition for the display on/off of the custom fields on test cases.
  711. if ($printingOptions['cfields'] && !is_null($exec_info))
  712. {
  713. $execution_id = $exec_info[0]['execution_id'];
  714. $cfields['execScope'] = $tc_mgr->html_table_of_custom_field_values($versionID,'execution',null,
  715. $execution_id, $tplan_id,
  716. $tprojectID,$cfieldFormatting);
  717. }
  718. if ($printingOptions['toc'])
  719. {
  720. $printingOptions['tocCode'] .= '<p style="padding-left: ' .
  721. (15*$level).'px;"><a href="#' . prefixToHTMLID('tc'.$id) . '">' .
  722. $name . '</a></p>';
  723. $code .= '<a name="' . prefixToHTMLID('tc'.$id) . '"></a>';
  724. }
  725. $code .= '<p>&nbsp;</p><div> <table class="tc" width="90%">';
  726. $code .= '<tr><th colspan="' . $cfg['tableColspan'] . '">' . $labels['test_case'] . " " .
  727. htmlspecialchars($external_id) . ": " . $name;
  728. // add test case version
  729. if($cfg['doc']->tc_version_enabled && isset($node['version']))
  730. {
  731. $code .= '&nbsp;<span style="font-size: 80%;"' . $cfg['gui']->role_separator_open .
  732. $labels['version'] . $cfg['gui']->title_separator_1 . $node['version'] .
  733. $cfg['gui']->role_separator_close . '</span>';
  734. }
  735. $code .= "</th></tr>\n";
  736. if ($printingOptions['author'])
  737. {
  738. $authorName = gendocGetUserName($db, $tcInfo['author_id']);
  739. $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' .
  740. '<span class="label">'.$labels['author'].':</span></td>';
  741. $code .= '<td colspan="' . ($cfg['tableColspan']-1) . '">' . $authorName;
  742. if (($tcInfo['updater_id'] > 0) && $tcInfo['updater_id'] != $tcInfo['author_id'])
  743. {
  744. // add updater if available and differs from author
  745. $updaterName = gendocGetUserName($db, $tcInfo['updater_id']);
  746. $code .= '<br />' . $labels['last_edit'] . " " . $updaterName;
  747. }
  748. $code .= "</td></tr>\n";
  749. }
  750. if ($printingOptions['body'] || $printingOptions['summary'])
  751. {
  752. $tcase_pieces = array('summary');
  753. }
  754. if ($printingOptions['body'])
  755. {
  756. $tcase_pieces[] = 'preconditions';
  757. $tcase_pieces[] = 'steps';
  758. // $tcase_pieces[] = 'expected_results';
  759. }
  760. if(!is_null($tcase_pieces))
  761. {
  762. // Multiple Test Case Steps Feature
  763. foreach($tcase_pieces as $key)
  764. {
  765. // 20090719 - franciscom - cf location
  766. if( $key == 'steps' )
  767. {
  768. if( isset($cfields['specScope']['before_steps_results']) )
  769. {
  770. $code .= $cfields['specScope']['before_steps_results'];
  771. }
  772. if ($tcInfo[$key] != '')
  773. {
  774. $code .= '<tr>' .
  775. '<td><span class="label">' . $labels['step_number'] .':</span></td>' .
  776. '<td><span class="label">' . $labels['step_actions'] .':</span></td>' .
  777. '<td><span class="label">' . $labels['expected_results'] .':</span></td></tr>';
  778. $loop2do = count($tcInfo[$key]);
  779. for($ydx=0 ; $ydx < $loop2do; $ydx++)
  780. {
  781. $code .= '<tr>' .
  782. '<td width="5">' . $tcInfo[$key][$ydx]['step_number'] . '</td>' .
  783. '<td>' . $tcInfo[$key][$ydx]['actions'] . '</td>' .
  784. '<td>' . $tcInfo[$key][$ydx]['expected_results'] . '</td>' .
  785. '</tr>';
  786. }
  787. }
  788. }
  789. else
  790. {
  791. // disable the field if it's empty
  792. if ($tcInfo[$key] != '')
  793. {
  794. $code .= '<tr><td colspan="' . $cfg['tableColspan'] . '"><span class="label">' . $labels[$key] .
  795. ':</span><br />' . $tcInfo[$key] . "</td></tr>";
  796. }
  797. }
  798. }
  799. }
  800. // Spacer
  801. $code .= '<tr><td colspan="' . $cfg['tableColspan'] . '">' . "</td></tr>";
  802. // 20090719 - franciscom - cf location
  803. $code .= $cfields['specScope']['standard_location'] . $cfields['execScope'];
  804. // generate test results data for test report
  805. if ($printingOptions['passfail'])
  806. {
  807. if ($exec_info)
  808. {
  809. $code .= buildTestExecResults($db,$cfg,$labels,$exec_info);
  810. }
  811. else
  812. {
  813. $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' .
  814. '<span class="label">' . $labels['last_exec_result'] . '</span></td>' .
  815. '<td colspan="' . ($cfg['tableColspan']-1) . '"><b>' . $labels["test_status_not_run"] .
  816. "</b></td></tr>\n";
  817. }
  818. }
  819. // collect REQ for TC
  820. // based on contribution by JMU (#1045)
  821. if ($printingOptions['requirement'])
  822. {
  823. if(!$req_mgr)
  824. {
  825. $req_mgr = new requirement_mgr($db);
  826. }
  827. $requirements = $req_mgr->get_all_for_tcase($id);
  828. $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top"><span class="label">'.
  829. $labels['reqs'].'</span>';
  830. $code .= '<td colspan="' . ($cfg['tableColspan']-1) . '">';
  831. if (sizeof($requirements))
  832. {
  833. foreach ($requirements as $req)
  834. {
  835. $code .= htmlspecialchars($req['req_doc_id'] . ": " . $req['title']) . "<br />";
  836. }
  837. }
  838. else
  839. {
  840. $code .= '&nbsp;' . $labels['none'] . '<br />';
  841. }
  842. $code .= "</td></tr>\n";
  843. }
  844. // collect keywords for TC
  845. // based on contribution by JMU (#1045)
  846. if ($printingOptions['keyword'])
  847. {
  848. $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top"><span class="label">'.
  849. $labels['keywords'].':</span>';
  850. $code .= '<td colspan="' . ($cfg['tableColspan']-1) . '">';
  851. $arrKeywords = $tc_mgr->getKeywords($id);
  852. if (sizeof($arrKeywords))
  853. {
  854. foreach ($arrKeywords as $kw)
  855. {
  856. $code .= htmlspecialchars($kw['keyword']) . "<br />";
  857. }
  858. }
  859. else
  860. {
  861. $code .= '&nbsp;' . $labels['none'] . '<br>';
  862. }
  863. $code .= "</td></tr>\n";
  864. }
  865. $code .= "</table>\n</div>\n";
  866. return $code;
  867. }
  868. /**
  869. * Remaining part of renderProjectNodeForPrinting
  870. *
  871. * @todo havlatm: refactor
  872. */
  873. function renderTOC(&$printingOptions)
  874. {
  875. $code = '';
  876. $printingOptions['toc_numbers'][1] = 0;
  877. if ($printingOptions['toc'])
  878. {
  879. $printingOptions['tocCode'] = '<h1 class="doclevel">' . lang_get('title_toc').'</h1><div class="toc">';
  880. $code .= "{{INSERT_TOC}}";
  881. }
  882. return $code;
  883. }
  884. /*
  885. function: renderTestSuiteNodeForPrinting
  886. args :
  887. returns:
  888. rev: 20090329 - franciscom - added ALWAYS Custom Fields
  889. 20081207 - franciscom - refactoring using static to decrease exec time.
  890. */
  891. function renderTestSuiteNodeForPrinting(&$db,&$node,&$printingOptions,$tocPrefix,$level,$tplan_id,$tproject_id)
  892. {
  893. static $tsuite_mgr;
  894. $labels = array('test_suite' => lang_get('test_suite'),'details' => lang_get('details'));
  895. $code = null;
  896. $name = isset($node['name']) ? htmlspecialchars($node['name']) : '';
  897. $title_separator = config_get('gui_title_separator_1');
  898. $cfields = array('design' => '');
  899. $cfieldFormatting=array('table_css_style' => 'class="cf"');
  900. $docHeadingNumbering = '';
  901. if ($printingOptions['headerNumbering']) {
  902. $docHeadingNumbering = "$tocPrefix. ";
  903. }
  904. if ($printingOptions['toc'])
  905. {
  906. $spacing = ($level == 2 && $tocPrefix != 1) ? "<br>" : "";
  907. $printingOptions['tocCode'] .= $spacing.'<b><p style="padding-left: '.(10*$level).'px;">' .
  908. '<a href="#' . prefixToHTMLID($tocPrefix) . '">' . $docHeadingNumbering . $name . "</a></p></b>\n";
  909. $code .= "<a name='". prefixToHTMLID($tocPrefix) . "'></a>\n";
  910. }
  911. $docHeadingLevel = $level - 1; //we would like to have html top heading H1 - H6
  912. $docHeadingLevel = ($docHeadingLevel > 6) ? 6 : $docHeadingLevel;
  913. $code .= "<h{$docHeadingLevel} class='doclevel'>" . $docHeadingNumbering . $labels['test_suite'] .
  914. $title_separator . $name . "</h{$docHeadingLevel}>\n";
  915. // ----- get Test Suite text -----------------
  916. if ($printingOptions['header'])
  917. {
  918. if( !$tsuite_mgr)
  919. {
  920. $tsuite_mgr = new testsuite($db);
  921. }
  922. $tInfo = $tsuite_mgr->get_by_id($node['id']);
  923. if ($tInfo['details'] != '')
  924. {
  925. $code .= '<div>'.$tInfo['details']. '</div>';
  926. }
  927. // get Custom fields
  928. // Attention: for test suites custom fields can not be edited during execution,
  929. // then we need to get just custom fields with scope 'design'
  930. foreach($cfields as $key => $value)
  931. {
  932. $cfields[$key] = $tsuite_mgr->html_table_of_custom_field_values($node['id'],$key,null,
  933. $tproject_id,$cfieldFormatting);
  934. if($cfields[$key] != "")
  935. {
  936. $add_br = true;
  937. $code .= '<p>' . $cfields[$key] . '</p>';
  938. }
  939. }
  940. }
  941. return $code;
  942. }
  943. /*
  944. function: renderTestPlanForPrinting
  945. args:
  946. returns:
  947. @internal revisions:
  948. 20100723 - asimon - BUGID 3459: added $platform_id
  949. */
  950. function renderTestPlanForPrinting(&$db, &$node, $item_type, &$printingOptions, $tocPrefix,
  951. $tcCnt, $level, $user_id, $tplan_id, $tprojectID, $platform_id)
  952. {
  953. $tProjectMgr = new testproject($db);
  954. $tcPrefix = $tProjectMgr->getTestCasePrefix($tprojectID);
  955. $code = renderTestSpecTreeForPrinting($db, $node, $item_type, $printingOptions,
  956. $tocPrefix, $tcCnt, $level, $user_id,
  957. $tplan_id, $tcPrefix, $tprojectID, $platform_id);
  958. return $code;
  959. }
  960. /**
  961. * Render HTML for estimated and real execute duration
  962. * based on contribution (BUGID 1670)
  963. *
  964. * @param array_of_strings $statistics
  965. * @return string HTML code
  966. */
  967. function renderTestDuration($statistics)
  968. {
  969. $output = '';
  970. $estimated_string = '';
  971. $real_string = '';
  972. $bEstimatedTimeAvailable = isset($statistics['estimated_execution']);
  973. $bRealTimeAvailable = isset($statistics['real_execution']);
  974. if( $bEstimatedTimeAvailable || $bRealTimeAvailable)
  975. {
  976. $output = "<div>\n";
  977. if($bEstimatedTimeAvailable)
  978. {
  979. $estimated_minutes = $statistics['estimated_execution']['minutes'];
  980. $tcase_qty = $statistics['estimated_execution']['tcase_qty'];
  981. if($estimated_minutes > 60)
  982. {
  983. $estimated_string = lang_get('estimated_time_hours') . round($estimated_minutes/60,2) ;
  984. }
  985. else
  986. {
  987. $estimated_string = lang_get('estimated_time_min') . $estimated_minutes;
  988. }
  989. $estimated_string = sprintf($estimated_string,$tcase_qty);
  990. $output .= '<p>' . $estimated_string . "</p>\n";
  991. }
  992. if($bRealTimeAvailable)
  993. {
  994. $real_minutes = $statistics['real_execution']['minutes'];
  995. $tcase_qty = $statistics['real_execution']['tcase_qty'];
  996. if($real_minutes > 0)
  997. {
  998. if($real_minutes > 60)
  999. {
  1000. $real_string = lang_get('real_time_hours') . round($real_minutes/60,2) ;
  1001. }
  1002. else
  1003. {
  1004. $real_string = lang_get('real_time_min') . $real_minutes;
  1005. }
  1006. $real_string = sprintf($real_string,$tcase_qty);
  1007. }
  1008. $output .= '<p>' . $real_string . "</p>\n";
  1009. }
  1010. $output .= "</div>\n";
  1011. }
  1012. return $output;
  1013. }
  1014. /**
  1015. * get final markup for HTML
  1016. *
  1017. * @return string HTML
  1018. **/
  1019. function renderEOF()
  1020. {
  1021. return "\n</body>\n</html>";
  1022. }
  1023. /**
  1024. * compose html text for metrics (meantime estimated time only)
  1025. *
  1026. * @return string html
  1027. */
  1028. function buildTestPlanMetrics($statistics)
  1029. {
  1030. $output = '<h1 class="doclevel">'.lang_get('title_nav_results')."</h1>\n";
  1031. $output .= renderTestDuration($statistics);
  1032. return $output;
  1033. }
  1034. /**
  1035. * utility function to allow easy reading of code
  1036. * on renderTestCaseForPrinting()
  1037. *
  1038. * @return map with configuration and labels
  1039. */
  1040. function initRenderTestCaseCfg(&$tcaseMgr)
  1041. {
  1042. $config = null;
  1043. $config['firstColWidth'] = '20%';
  1044. $config['tableColspan'] = 3;
  1045. $config['doc'] = config_get('document_generator');
  1046. $config['gui'] = config_get('gui');
  1047. $config['testcase'] = config_get('testcase_cfg');
  1048. $config['results'] = config_get('results');
  1049. foreach($config['results']['code_status'] as $key => $value)
  1050. {
  1051. $config['status_labels'][$key] =
  1052. "check your \$tlCfg->results['status_label'] configuration ";
  1053. if( isset($config['results']['status_label'][$value]) )
  1054. {
  1055. $config['status_labels'][$key] = lang_get($config['results']['status_label'][$value]);
  1056. }
  1057. }
  1058. // 20100306 - contribution by romans
  1059. // BUGID 0003235: Printing Out Test Report Shows empty Column Headers for "Steps" and "Step Actions"
  1060. $labelsKeys=array('last_exec_result', 'testnotes', 'none', 'reqs','author', 'summary',
  1061. 'steps', 'expected_results','build', 'test_case', 'keywords','version',
  1062. 'test_status_not_run', 'not_aplicable', 'bugs','tester','preconditions',
  1063. 'step_number', 'step_actions', 'last_edit');
  1064. $labelsQty=count($labelsKeys);
  1065. for($idx=0; $idx < $labelsQty; $idx++)
  1066. {
  1067. $labels[$labelsKeys[$idx]] = lang_get($labelsKeys[$idx]);
  1068. }
  1069. return array($config,$labels);
  1070. }
  1071. /**
  1072. *
  1073. *
  1074. */
  1075. function buildTestExecResults(&$dbHandler,$cfg,$labels,$exec_info)
  1076. {
  1077. $out='';
  1078. $testStatus = $cfg['status_labels'][$exec_info[0]['status']];
  1079. $testerName = gendocGetUserName($dbHandler, $exec_info[0]['tester_id']);
  1080. $executionNotes = $exec_info[0]['notes'];
  1081. $out .= '<tr><td width="20%" valign="top">' .
  1082. '<span class="label">' . $labels['last_exec_result'] . ':</span></td>' .
  1083. '<td><b>' . $testStatus . "</b></td></tr>\n" .
  1084. '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . $labels['build'] .'</td>' .
  1085. '<td>' . htmlspecialchars($exec_info[0]['build_name']) . "</b></td></tr>\n" .
  1086. '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . $labels['tester'] .'</td>' .
  1087. '<td>' . $testerName . "</b></td></tr>\n";
  1088. if ($executionNotes != '') // show exection notes is not empty
  1089. {
  1090. $out .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">'.$labels['testnotes'] . '</td>' .
  1091. '<td>' . nl2br($executionNotes) . "</td></tr>\n";
  1092. }
  1093. $bug_interface = config_get('bugInterface');
  1094. if ($bug_interface != 'NO')
  1095. {
  1096. // amitkhullar-BUGID 2207 - Code to Display linked bugs to a TC in Test Report
  1097. $bugs = get_bugs_for_exec($dbHandler,$bug_interface,$exec_info[0]['execution_id']);
  1098. if ($bugs)
  1099. {
  1100. $bugString = '';
  1101. foreach($bugs as $bugID => $bugInfo)
  1102. {
  1103. $bugString .= $bugInfo['link_to_bts']."<br />";
  1104. }
  1105. $out .= '<tr><td colspan="' . $cfg['tableColspan'] .
  1106. '" width="' . $cfg['firstColWidth'] . '" valign="top">' .
  1107. $labels['bugs'] . '</td><td>' . $bugString ."</td></tr>\n";
  1108. }
  1109. }
  1110. return $out;
  1111. }
  1112. /**
  1113. * Render HTML header for a given platform.
  1114. * Also adds code to $printingOptions['tocCode']
  1115. */
  1116. function renderPlatformHeading($tocPrefix, $platform_id, $platform_name, &$printingOptions)
  1117. {
  1118. $platformLabel = lang_get('platform');
  1119. $platform_name = htmlspecialchars($platform_name);
  1120. $printingOptions['tocCode'] .= '<p><a href="#' . prefixToHTMLID($tocPrefix) . '">' .
  1121. $platformLabel . ':' . $platform_name . '</a></p>';
  1122. return '<h1 class="doclevel" id="' . prefixToHTMLID($tocPrefix) . "\">$tocPrefix $platformLabel: $platform_name</h1>";
  1123. }
  1124. /**
  1125. * simple utility function, to avoid lot of copy and paste
  1126. * given an string, return an string useful to jump to an anchor on document
  1127. */
  1128. function prefixToHTMLID($string2convert,$anchor_prefix='toc_')
  1129. {
  1130. return $anchor_prefix . str_replace('.', '_', $string2convert);
  1131. }
  1132. ?>