xref: /plugin/acknowledge/_test/StatsTest.php (revision c2e33bcede677b26c01ce484dd9ed10c198ffb08)
1<?php
2
3namespace dokuwiki\plugin\acknowledge\test;
4
5use DokuWikiTest;
6
7/**
8 * Tests for the acknowledgement statistics aggregation
9 * (helper_plugin_acknowledge::getStatistics).
10 *
11 * Verifies the per-namespace and wiki-wide completion counts, @group expansion,
12 * and the current-vs-outdated semantics.
13 *
14 * @group plugin_acknowledge
15 * @group plugins
16 */
17class StatsTest extends DokuWikiTest
18{
19    /** @var array */
20    protected $pluginsEnabled = ['acknowledge', 'sqlite'];
21
22    /** @var \helper_plugin_acknowledge */
23    protected $helper;
24
25    public static function setUpBeforeClass(): void
26    {
27        parent::setUpBeforeClass();
28        /** @var \auth_plugin_authplain $auth */
29        global $auth;
30        $auth->createUser('max', 'none', 'max', 'max@example.com', ['super']);
31        $auth->createUser('regular', 'none', 'regular', 'regular@example.com', ['user']);
32    }
33
34    public function setUp(): void
35    {
36        parent::setUp();
37        $this->helper = plugin_load('helper', 'acknowledge');
38
39        $db = $this->helper->getDB();
40
41        // pages across two top-level namespaces (lastmod 1000), incl. a sub-namespace page
42        // that must roll up into its top-level namespace, plus a tracked page without assignees
43        $db->query(
44            "REPLACE INTO pages(page,lastmod) VALUES
45                ('stats1:a', 1000),
46                ('stats1:b', 1000),
47                ('stats1:sub:d', 1000),
48                ('stats2:c', 1000),
49                ('stats1:noassign', 1000)"
50        );
51
52        // stats1:a -> required {regular, max(@super)}; regular current, max outdated
53        $this->helper->setPageAssignees('stats1:a', 'regular, @super');
54        $this->helper->importAcknowledgement('stats1:a', 'regular', 2000);
55        $this->helper->importAcknowledgement('stats1:a', 'max', 500);
56
57        // stats1:b -> required {regular}; current -> fully acknowledged
58        $this->helper->setPageAssignees('stats1:b', 'regular');
59        $this->helper->importAcknowledgement('stats1:b', 'regular', 2000);
60
61        // stats1:sub:d -> required {regular}; current -> fully acknowledged; rolls up into 'stats1'
62        $this->helper->setPageAssignees('stats1:sub:d', 'regular');
63        $this->helper->importAcknowledgement('stats1:sub:d', 'regular', 2000);
64
65        // stats2:c -> required {max(@super)}; never acknowledged
66        $this->helper->setPageAssignees('stats2:c', '@super');
67    }
68
69    /**
70     * Whole-wiki aggregation across both namespaces.
71     */
72    public function testTotals()
73    {
74        $stats = $this->helper->getStatistics();
75
76        self::assertEquals(
77            ['required' => 5, 'acked' => 3, 'pages' => 4],
78            $stats['total']
79        );
80    }
81
82    /**
83     * Root drill-down: pages are grouped by their top-level namespace, plus @group expansion,
84     * current-vs-outdated handling, and the haschildren flag for namespaces with deeper content.
85     */
86    public function testNamespaceBreakdown()
87    {
88        $stats = $this->helper->getStatistics();
89        $ns = $stats['namespaces'];
90
91        self::assertEquals(
92            ['required' => 4, 'acked' => 3, 'pages' => 3, 'haschildren' => true],
93            $ns['stats1']
94        );
95
96        self::assertEquals(
97            ['required' => 1, 'acked' => 0, 'pages' => 1, 'haschildren' => false],
98            $ns['stats2']
99        );
100    }
101
102    /**
103     * Pages without assignees are excluded from the statistics.
104     */
105    public function testPageWithoutAssigneesExcluded()
106    {
107        $stats = $this->helper->getStatistics();
108
109        // only stats1 and stats2 namespaces, noassign contributes nothing
110        self::assertEquals(['stats1', 'stats2'], array_keys($stats['namespaces']));
111        self::assertSame(4, $stats['total']['pages']);
112    }
113
114    /**
115     * Drilling into a namespace groups pages by their immediate child namespace, while the
116     * total stays wiki-wide.
117     */
118    public function testDrilldown()
119    {
120        $stats = $this->helper->getStatistics('stats1');
121
122        // total is always the whole wiki, regardless of the drill-down namespace
123        self::assertEquals(
124            ['required' => 5, 'acked' => 3, 'pages' => 4],
125            $stats['total']
126        );
127
128        // within stats1: direct pages (a + b) group under 'stats1', the sub-namespace page
129        // groups under 'stats1:sub'; stats2 is out of scope
130        self::assertEquals(['stats1', 'stats1:sub'], array_keys($stats['namespaces']));
131
132        // 'stats1' self group = direct pages a + b: required max+regular(a)+regular(b) = 3,
133        // acked regular(a)+regular(b) = 2; no pages deeper than stats1:* here -> haschildren false
134        self::assertEquals(
135            ['required' => 3, 'acked' => 2, 'pages' => 2, 'haschildren' => false],
136            $stats['namespaces']['stats1']
137        );
138
139        // 'stats1:sub' = page sub:d: required regular = 1, acked regular = 1
140        self::assertEquals(
141            ['required' => 1, 'acked' => 1, 'pages' => 1, 'haschildren' => false],
142            $stats['namespaces']['stats1:sub']
143        );
144    }
145}
146