Note: this session replaces
"What type of testing is good for me?"







Woh nedes a sepll cehcker?
... computers aren't so forgiving
They do exactly as they are told,
no more and no less.
Donald Knuth Knuth (1968), "The Art of Computer Programming"
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
is executed like...
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) {
goto fail;
}
goto fail;
...the rest of the code is not executed!
The "goto fail" bug could have been caught by static analysis
Source: Martin Fowler
Anything you can learn from code without executing it.
if (($err = SSLHashSHA1::update($hashCtx, $signedParams)) != 0)
goto fail;
goto fail;
Read the file off disk and look for a pattern.
protected function doLoadMultiple(array $names, $immutable = TRUE) {
...
if (isset($GLOBALS['config'][$name])) {
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
...
protected function formSingleElement(FieldItemListInterface $items, $delta...
$entity = $items->getEntity();
$element += array(
'#field_parents' => $form['#parents'],
// Only the first widget should be required.
'#required' => $delta == 0 && $this->fieldDefinition->isRequired(),
'#delta' => $delta,
'#weight' => $delta,
);
$element = $this->formElement($items, $delta, $element, $form, $form_state);
if ($element) {
...
If it stinks, change it.
- Grandma Beck, "Refactoring"
protected function doLoadMultiple(array $names, $immutable = TRUE) {
...
if (isset($GLOBALS['config'][$name])) {
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
...
protected function formSingleElement(FieldItemListInterface $items, $delta...
$entity = $items->getEntity();
$element += array(
'#field_parents' => $form['#parents'],
// Only the first widget should be required.
'#required' => $delta == 0 && $this->fieldDefinition->isRequired(),
'#delta' => $delta,
'#weight' => $delta,
);
$element = $this->formElement($items, $delta, $element, $form, $form_state);
if ($element) {
...
$entity is supposed to do.$entity a bug?
private function getProxyInstantiator()
{
if (!$this->proxyInstantiator) {
$this->proxyInstantiator = new RealServiceInstantiator();
}
...
class EntityType implements EntityTypeInterface {
public function get($property) {
public function set($property, $value) {
public function isStaticallyCacheable() {
public function isRenderCacheable() {
public function isPersistentlyCacheable() {
public function getKeys() {
public function getKey($key) {
public function hasKey($key) {
public function id() {
public function getProvider() {
public function getClass() {
public function getOriginalClass() {
public function setClass($class) {
public function isSubclassOf($class) {
public function getHandlerClasses() {
public function getHandlerClass($handler_type, $nested = FALSE) {
public function setHandlerClass($handler_type, $value) {
public function hasHandlerClass($handler_type, $nested = FALSE) {
public function getStorageClass() {
public function setStorageClass($class) {
... 49 more methods!
class WorkspaceController extends ControllerBase {
public function add() {
$types = WorkspaceType::loadMultiple();
if ($types && count($types) == 1) {
$type = reset($types);
return $this->addForm($type);
}
...
::loadMultiple()
public function update(WorkspacePointerInterface $source, WorkspacePointerInterface $target) {
return $this->doReplication($source, $target);
}
update is generic, why is it just a wrapper to doReplication?
public function disableEntityTypes() {
foreach ($entity_types as $entity_type_id => $entity_type) {
try {
if ($storage->hasData()) {
catch (\Exception $e) {
if ($has_data[$entity_type_id]) {
if ($entity_type_id == 'file') {
foreach ($entity_manager->getDefinitions() as $entity_type) {
if ($entity_type->isSubclassOf(FieldableEntityInterface::CLASS)) {
foreach ($entity_manager->getFieldStorageDefinitions($entity_type_id)...
if ($storage_definition->getProvider() == 'multiversion' && !$storage...
foreach ($enabled_entity_types as $entity_type_id) {
foreach ($entity_types as $entity_type_id => $entity_type) {
if ($has_data[$entity_type_id]) {
...
...
namespace Drupal\multiversion;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Database\Connection;
use Drupal\multiversion\Workspace\WorkspaceManagerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\Serializer\Serializer;
class MultiversionManager implements MultiversionManagerInterface, ContainerAwareInterface {
...
A static analysis platform, free for open source (on GitHub).
Examples on GitHub:
github.com/josephdpurcell/code-climate-and-drupal
---
engines:
phpmd:
enabled: true
config:
file_extensions: "php,inc,module,install"
rulesets: ".phpmd.xml"
phpcodesniffer:
enabled: true
config:
file_extensions: "php,inc,module,install"
encoding: utf-8
standard: "Drupal"
ignore_warnings: true
ratings:
paths:
- "web/modules/custom/**.php"
- "web/modules/custom/**.inc"
- "web/modules/custom/**.module"
- "web/modules/custom/**.install"
exclude_paths:
- conf
- web/core
- web/modules/contrib
- web/profiles
- web/sites
- web/themes
- web/*.php
<?xml version="1.0"?>
<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3...
<description>
A PMD Ruleset for Drupal coding standards.
</description>
<!-- Code Size -->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity"/>
<rule ref="rulesets/codesize.xml/NPathComplexity"/>
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>
<rule ref="rulesets/codesize.xml/ExcessiveClassLength"/>
<rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>
<rule ref="rulesets/codesize.xml/ExcessivePublicCount"/>
<rule ref="rulesets/codesize.xml/TooManyFields"/>
...
Source: Continuous Integration by Paul Duvall
...and you're wasting time.
Source: github.com/18F/micropurchase/pull/524
Source: github.com/18F/micropurchase/pull/466
Source: codeclimate.com/github/18F/micropurchase/pull/466
Drupal 8 code metrics generated by phpmetrics.org, see results.
Speak for the code.
Come to the sprints on Friday!
Slides: github.com/josephdpurcell/code-climate-and-drupal
Want help setting up static analysis or Code Climate?
Find me at @josephdpurcell.