Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
90.00% |
45 / 50 |
|
66.67% |
2 / 3 |
CRAP | |
0.00% |
0 / 1 |
| FunctionsByTestsPager | |
90.00% |
45 / 50 |
|
66.67% |
2 / 3 |
9.08 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getQueryInfo | |
85.71% |
30 / 35 |
|
0.00% |
0 / 1 |
6.10 | |||
| formatRow | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * WikiLambda FunctionsByTestsPager extends AbstractZObjectPager by |
| 4 | * adding filter conditions to the base table of all zobjects and |
| 5 | * their preferred labels given by AbstractZObjectPager::getQueryInfo |
| 6 | * |
| 7 | * @file |
| 8 | * @ingroup Extensions |
| 9 | * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt |
| 10 | * @license MIT |
| 11 | */ |
| 12 | |
| 13 | namespace MediaWiki\Extension\WikiLambda\Pagers; |
| 14 | |
| 15 | use MediaWiki\Context\IContextSource; |
| 16 | use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry; |
| 17 | use MediaWiki\Extension\WikiLambda\ZObjectStore; |
| 18 | use Wikimedia\Rdbms\Subquery; |
| 19 | |
| 20 | /** |
| 21 | * Pages Functions filtered by their testing status and quality. |
| 22 | */ |
| 23 | class FunctionsByTestsPager extends AbstractZObjectPager { |
| 24 | |
| 25 | private array $filters; |
| 26 | |
| 27 | /** |
| 28 | * @param IContextSource|null $context Context. |
| 29 | * @param ZObjectStore $zObjectStore |
| 30 | * @param array $languageZids |
| 31 | * @param bool|null $excludePreDefined |
| 32 | * @param array|null $filters [ min, max, connected, pending, pass, fail ] |
| 33 | */ |
| 34 | public function __construct( |
| 35 | $context, $zObjectStore, $languageZids, $excludePreDefined = null, $filters = [] |
| 36 | ) { |
| 37 | parent::__construct( $context, $zObjectStore, $languageZids, null, $excludePreDefined ); |
| 38 | |
| 39 | $this->filters = $filters; |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * Gets the base conditions from the parent class and adds the |
| 44 | * additional conditions for this pager, depending on the filters. |
| 45 | * This pager inner joins the preferredLabels table returned by the |
| 46 | * AbstractZObjectPager with a table with all function ids and their |
| 47 | * relevant test counts: |
| 48 | * - all_tests: All the tests created for each function. |
| 49 | * - connected_tests: Number of connected tests for each function. |
| 50 | * - failing_tests: Number of tests failing for each function |
| 51 | * (against at least one connected implementation) |
| 52 | * - matching_tests: Number of tests that match the conditions passed |
| 53 | * as input in the Request: connected status and failure/success status. |
| 54 | * |
| 55 | * @return array |
| 56 | */ |
| 57 | public function getQueryInfo() { |
| 58 | // Get base queryInfo from parent |
| 59 | $queryInfo = parent::getQueryInfo(); |
| 60 | |
| 61 | $min = $this->filters[ 'min' ]; |
| 62 | $max = $this->filters[ 'max' ]; |
| 63 | $connected = $this->filters[ 'connected' ]; |
| 64 | $pending = $this->filters[ 'pending' ]; |
| 65 | $pass = $this->filters[ 'pass' ]; |
| 66 | $fail = $this->filters[ 'fail' ]; |
| 67 | |
| 68 | $testStatus = $this->getZObjectStore()->getTestStatusQuery(); |
| 69 | $testFilters = []; |
| 70 | // Connection status filter: |
| 71 | // * Add where clause only if one value is selected |
| 72 | // * If both true or both false, leave unfiltered |
| 73 | if ( $connected !== $pending ) { |
| 74 | $testFilters[] = 'is_connected = ' . (int)$connected; |
| 75 | } |
| 76 | // Test results filter: |
| 77 | // * Add where clause only if one value is selected |
| 78 | // * If both true or both false, leave unfiltered |
| 79 | if ( $pass !== $fail ) { |
| 80 | $testFilters[] = 'is_passing = ' . (int)$pass; |
| 81 | } |
| 82 | |
| 83 | // Conditional to count matching tests, if no filters count 1 per entry |
| 84 | $matchingConditional = 1; |
| 85 | if ( count( $testFilters ) > 0 ) { |
| 86 | $matchingConditional = $this->getDatabase()->conditional( $testFilters, '1', 'NULL' ); |
| 87 | } |
| 88 | // Table with all function ids and their test counts: |
| 89 | $filteredFunctions = $this->getDatabase()->newSelectQueryBuilder() |
| 90 | ->select( [ |
| 91 | 'function_zid', |
| 92 | 'all_tests', |
| 93 | 'connected_tests' => 'COUNT( CASE WHEN is_connected = 1 THEN 1 END )', |
| 94 | 'failing_tests' => 'COUNT( CASE WHEN is_passing = 0 THEN 1 END )', |
| 95 | 'matching_tests' => 'COUNT( ' . $matchingConditional . ' )' |
| 96 | ] ) |
| 97 | ->from( new Subquery( $testStatus ), 'filtered_functions' ) |
| 98 | ->groupBy( [ 'function_zid', 'all_tests' ] ); |
| 99 | |
| 100 | // Add additional data to parent queryInfo |
| 101 | // 1. Return all test counts in the main select |
| 102 | array_push( $queryInfo[ 'fields' ], 'all_tests', 'matching_tests', 'connected_tests', 'failing_tests' ); |
| 103 | // 2. Join filteredFunctions with preferredLabels |
| 104 | $queryInfo[ 'tables' ][ 'tests' ] = new Subquery( $filteredFunctions->getSQL() ); |
| 105 | $queryInfo[ 'join_conds' ][ 'tests' ] = [ 'LEFT JOIN', 'wlzl_zobject_zid = tests.function_zid' ]; |
| 106 | // 3. Return functions for which matching_tests count is less than max. |
| 107 | $queryInfo[ 'conds' ][ 'wlzl_type' ] = ZTypeRegistry::Z_FUNCTION; |
| 108 | if ( $max > -1 ) { |
| 109 | $queryInfo[ 'conds' ][] = "matching_tests <= $max"; |
| 110 | } |
| 111 | if ( $min > 0 ) { |
| 112 | $queryInfo[ 'conds' ][] = "matching_tests >= $min"; |
| 113 | } |
| 114 | |
| 115 | return $queryInfo; |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * @param \stdClass $row |
| 120 | * @return string |
| 121 | */ |
| 122 | public function formatRow( $row ) { |
| 123 | $zid = $row->wlzl_zobject_zid; |
| 124 | $label = $row->wlzl_label; |
| 125 | |
| 126 | $functionInfo = "# [[$zid|$label]] ($zid)"; |
| 127 | |
| 128 | $tests = $row->all_tests; |
| 129 | $fail = $row->failing_tests; |
| 130 | $conn = $row->connected_tests; |
| 131 | |
| 132 | $testsMsg = $this->msg( 'wikilambda-special-functionsbytests-row-tests' )->params( $tests )->text(); |
| 133 | $failMsg = $this->msg( 'wikilambda-special-functionsbytests-row-failing' )->params( $fail )->text(); |
| 134 | $connMsg = $this->msg( 'wikilambda-special-functionsbytests-row-connected' )->params( $conn )->text(); |
| 135 | |
| 136 | $testInfo = "$testsMsg, " |
| 137 | . "<span class='ext-wikilambda-special-tests-connected'>$connMsg</span>" |
| 138 | . ( (int)$fail == 0 ? '' : ", <span class='ext-wikilambda-special-tests-failing'>$failMsg</span>" ); |
| 139 | |
| 140 | return $functionInfo . ' - ' . $this->msg( 'parentheses' )->params( $testInfo )->text() . "\n"; |
| 141 | } |
| 142 | } |