public function getViewData(array $params = array()) { $junitReportFile = $this->getPtrProjectBuild()->getBuildDir() . CINTIENT_JUNIT_REPORT_FILENAME; if (!is_file($junitReportFile)) { SystemEvent::raise(SystemEvent::ERROR, "Junit file not found. [PID={$this->getProjectId()}] [BUILD={$this->getProjectBuildId()}] [FILE={$junitReportFile}]", __METHOD__); return false; } try { $xml = new SimpleXMLElement($junitReportFile, 0, true); } catch (Exception $e) { SystemEvent::raise(SystemEvent::ERROR, "Problems processing Junit XML file. [PID={$this->getProjectId()}] [BUILD={$this->getProjectBuildId()}]", __METHOD__); return false; } // Apparently using call_user_func(__FUNCTION__) inside a closure, // doesn't work... Anyway I'm just going for a closure here, to // avoid the whole function definition crap here, inside a method. // // This closure takes a SimpleXMLElement loaded with the Junit report // and searches for the first element with a file attribute. That // level is the Class Test level, and what we want here is to iterate // over all class tests. $f = function ($node) use(&$parent, &$f) { if (isset($node->attributes()->file)) { return $parent->children(); } else { $parent = $node; return $f($node->children()); } }; $parent = $xml; $classTestsXml = $f($xml->children()); $classes = array(); foreach ($classTestsXml as $node) { $imageFilename = ''; $methodsNames = array(); $methods = array(); $class = new TestClass(); $class->setName((string) $node->attributes()->name); $class->setFile((string) $node->attributes()->file); $class->setTests((string) $node->attributes()->tests); $class->setAssertions((string) $node->attributes()->assertions); $class->setFailures((string) $node->attributes()->failures); $class->setErrors((string) $node->attributes()->errors); $class->setTime((string) $node->attributes()->time); $class->setChartFilename(md5($this->getProjectId() . $this->getProjectBuildId() . $class->getFile()) . '.png'); // Right here we're exactly at the test class (file) root level, // with level 1 being the unit test (method of the original class) // and level 2 being the various datasets used in the test (each a // test case). foreach ($node->children() as $methodXml) { $time = (double) $methodXml->attributes()->time * 1000; // to milliseconds $methodsNames[] = (string) $methodXml->attributes()->name; $f = (double) $methodXml->attributes()->failures * $time / (double) $methodXml->attributes()->assertions; $method = new TestMethod(); $method->setName((string) $methodXml->attributes()->name); $method->setTests((string) $methodXml->attributes()->tests); $method->setAssertions((string) $methodXml->attributes()->assertions); $method->setFailures((string) $methodXml->attributes()->failures); $method->setErrors((string) $methodXml->attributes()->errors); $method->setTime((string) $methodXml->attributes()->time); $method->setCalculatedOks((double) $time - (double) $f); $method->setCalculatedFaileds($f); $methods[] = $method; } $class->setTestMethods($methods); $classes[] = $class; } $ret = array(); $ret['project_buildJunit'] = $classes; return $ret; }