xref: /plugin/structnotification/_test/NotificationTest.php (revision e4050f96b6dcfab785452ad4f1478151d79238be)
1*e4050f96SAnna Dabrowska<?php
2*e4050f96SAnna Dabrowska
3*e4050f96SAnna Dabrowskanamespace dokuwiki\plugin\structnotification\test;
4*e4050f96SAnna Dabrowska
5*e4050f96SAnna Dabrowskause dokuwiki\plugin\struct\meta\Value;
6*e4050f96SAnna Dabrowskause dokuwiki\plugin\struct\meta\Column;
7*e4050f96SAnna Dabrowska
8*e4050f96SAnna Dabrowska/**
9*e4050f96SAnna Dabrowska * Unit tests for structnotification plugin
10*e4050f96SAnna Dabrowska *
11*e4050f96SAnna Dabrowska * @group plugin_structnotification
12*e4050f96SAnna Dabrowska * @group plugins
13*e4050f96SAnna Dabrowska */
14*e4050f96SAnna Dabrowskaclass NotificationTest extends \DokuWikiTest
15*e4050f96SAnna Dabrowska{
16*e4050f96SAnna Dabrowska    protected $pluginsEnabled = ['struct', 'structnotification'];
17*e4050f96SAnna Dabrowska
18*e4050f96SAnna Dabrowska    /** @var \action_plugin_structnotification_notification */
19*e4050f96SAnna Dabrowska    protected $action;
20*e4050f96SAnna Dabrowska
21*e4050f96SAnna Dabrowska    public function setUp(): void
22*e4050f96SAnna Dabrowska    {
23*e4050f96SAnna Dabrowska        parent::setUp();
24*e4050f96SAnna Dabrowska        $this->action = new \action_plugin_structnotification_notification();
25*e4050f96SAnna Dabrowska    }
26*e4050f96SAnna Dabrowska
27*e4050f96SAnna Dabrowska    /**
28*e4050f96SAnna Dabrowska     * Test date parsing with different formats
29*e4050f96SAnna Dabrowska     */
30*e4050f96SAnna Dabrowska    public function test_predicateTrue_date_formats()
31*e4050f96SAnna Dabrowska    {
32*e4050f96SAnna Dabrowska        $datetime = date('Y-m-d H:i:s', strtotime('+5 days'));
33*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$datetime, 'before', 10]));
34*e4050f96SAnna Dabrowska
35*e4050f96SAnna Dabrowska        $datetime = date('Y/d/m', strtotime('+5 days'));
36*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$datetime, 'before', 10]));
37*e4050f96SAnna Dabrowska    }
38*e4050f96SAnna Dabrowska
39*e4050f96SAnna Dabrowska    /**
40*e4050f96SAnna Dabrowska     * Test predicateTrue() with 'before' operator
41*e4050f96SAnna Dabrowska     */
42*e4050f96SAnna Dabrowska    public function test_predicateTrue_before()
43*e4050f96SAnna Dabrowska    {
44*e4050f96SAnna Dabrowska        // Test date that is 5 days from now should match "10 days before"
45*e4050f96SAnna Dabrowska        $futureDate = date('Y-m-d', strtotime('+5 days'));
46*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$futureDate, 'before', 10]));
47*e4050f96SAnna Dabrowska
48*e4050f96SAnna Dabrowska        // Test date that is 15 days from now should not match "10 days before"
49*e4050f96SAnna Dabrowska        $farFutureDate = date('Y-m-d', strtotime('+15 days'));
50*e4050f96SAnna Dabrowska        $this->assertFalse($this->callPrivateMethod('predicateTrue', [$farFutureDate, 'before', 10]));
51*e4050f96SAnna Dabrowska
52*e4050f96SAnna Dabrowska        // Test today should match "1 day before"
53*e4050f96SAnna Dabrowska        $today = date('Y-m-d');
54*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$today, 'before', 1]));
55*e4050f96SAnna Dabrowska    }
56*e4050f96SAnna Dabrowska
57*e4050f96SAnna Dabrowska    /**
58*e4050f96SAnna Dabrowska     * Test predicateTrue() with 'after' operator
59*e4050f96SAnna Dabrowska     */
60*e4050f96SAnna Dabrowska    public function test_predicateTrue_after()
61*e4050f96SAnna Dabrowska    {
62*e4050f96SAnna Dabrowska        // Test date that is 15 days ago should match "10 days after"
63*e4050f96SAnna Dabrowska        $farPastDate = date('Y-m-d', strtotime('-15 days'));
64*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$farPastDate, 'after', 10]));
65*e4050f96SAnna Dabrowska
66*e4050f96SAnna Dabrowska        // Test date that is 5 days ago should not match "10 days after"
67*e4050f96SAnna Dabrowska        $pastDate = date('Y-m-d', strtotime('-5 days'));
68*e4050f96SAnna Dabrowska        $this->assertFalse($this->callPrivateMethod('predicateTrue', [$pastDate, 'after', 10]));
69*e4050f96SAnna Dabrowska
70*e4050f96SAnna Dabrowska        // Test today should not match "1 day after"
71*e4050f96SAnna Dabrowska        $today = date('Y-m-d');
72*e4050f96SAnna Dabrowska        $this->assertFalse($this->callPrivateMethod('predicateTrue', [$today, 'after', 1]));
73*e4050f96SAnna Dabrowska    }
74*e4050f96SAnna Dabrowska
75*e4050f96SAnna Dabrowska    /**
76*e4050f96SAnna Dabrowska     * Test predicateTrue() with invalid operator
77*e4050f96SAnna Dabrowska     */
78*e4050f96SAnna Dabrowska    public function test_predicateTrue_invalid_operator()
79*e4050f96SAnna Dabrowska    {
80*e4050f96SAnna Dabrowska        $today = date('Y-m-d');
81*e4050f96SAnna Dabrowska        $this->assertFalse($this->callPrivateMethod('predicateTrue', [$today, 'invalid', 5]));
82*e4050f96SAnna Dabrowska    }
83*e4050f96SAnna Dabrowska
84*e4050f96SAnna Dabrowska    /**
85*e4050f96SAnna Dabrowska     * Test edge cases for predicateTrue()
86*e4050f96SAnna Dabrowska     */
87*e4050f96SAnna Dabrowska    public function test_predicateTrue_edge_cases()
88*e4050f96SAnna Dabrowska    {
89*e4050f96SAnna Dabrowska        // Test with 0 days - both should match today
90*e4050f96SAnna Dabrowska        $today = date('Y-m-d');
91*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$today, 'before', 0]));
92*e4050f96SAnna Dabrowska        $this->assertTrue($this->callPrivateMethod('predicateTrue', [$today, 'after', 0]));
93*e4050f96SAnna Dabrowska    }
94*e4050f96SAnna Dabrowska
95*e4050f96SAnna Dabrowska    /**
96*e4050f96SAnna Dabrowska     * Test replacePlaceholders()
97*e4050f96SAnna Dabrowska     */
98*e4050f96SAnna Dabrowska    public function test_replacePlaceholders()
99*e4050f96SAnna Dabrowska    {
100*e4050f96SAnna Dabrowska        // Mock Value objects
101*e4050f96SAnna Dabrowska        $value1 = $this->createMockValue('schema1', 'field1', 'Test Value 1');
102*e4050f96SAnna Dabrowska        $value2 = $this->createMockValue('schema1', 'field2', 'Test Value 2');
103*e4050f96SAnna Dabrowska        $values = [$value1, $value2];
104*e4050f96SAnna Dabrowska
105*e4050f96SAnna Dabrowska        $message = 'Hello @@schema1.field1@@, your @@schema1.field2@@ is ready.';
106*e4050f96SAnna Dabrowska        $expected = 'Hello Test Value 1, your Test Value 2 is ready.';
107*e4050f96SAnna Dabrowska
108*e4050f96SAnna Dabrowska        $result = $this->callPrivateMethod('replacePlaceholders', [$message, $values]);
109*e4050f96SAnna Dabrowska        $this->assertEquals($expected, $result);
110*e4050f96SAnna Dabrowska    }
111*e4050f96SAnna Dabrowska
112*e4050f96SAnna Dabrowska    /**
113*e4050f96SAnna Dabrowska     * Test replacePlaceholders with no matches
114*e4050f96SAnna Dabrowska     */
115*e4050f96SAnna Dabrowska    public function test_replacePlaceholders_no_matches()
116*e4050f96SAnna Dabrowska    {
117*e4050f96SAnna Dabrowska        $value1 = $this->createMockValue('schema1', 'field1', 'Test Value 1');
118*e4050f96SAnna Dabrowska        $values = [$value1];
119*e4050f96SAnna Dabrowska
120*e4050f96SAnna Dabrowska        $message = 'Hello @@schema2.field2@@, no replacement here.';
121*e4050f96SAnna Dabrowska        $expected = 'Hello @@schema2.field2@@, no replacement here.';
122*e4050f96SAnna Dabrowska
123*e4050f96SAnna Dabrowska        $result = $this->callPrivateMethod('replacePlaceholders', [$message, $values]);
124*e4050f96SAnna Dabrowska        $this->assertEquals($expected, $result);
125*e4050f96SAnna Dabrowska    }
126*e4050f96SAnna Dabrowska
127*e4050f96SAnna Dabrowska    /**
128*e4050f96SAnna Dabrowska     * Test early return in addFiltersToSearch()
129*e4050f96SAnna Dabrowska     */
130*e4050f96SAnna Dabrowska    public function test_addFiltersToSearch_empty_filters()
131*e4050f96SAnna Dabrowska    {
132*e4050f96SAnna Dabrowska        $search = $this->createMock(\dokuwiki\plugin\struct\meta\Search::class);
133*e4050f96SAnna Dabrowska        $search->expects($this->never())->method('addFilter');
134*e4050f96SAnna Dabrowska
135*e4050f96SAnna Dabrowska        $this->callPrivateMethod('addFiltersToSearch', [&$search, '']);
136*e4050f96SAnna Dabrowska    }
137*e4050f96SAnna Dabrowska
138*e4050f96SAnna Dabrowska    /**
139*e4050f96SAnna Dabrowska     * Test addFiltersToSearch method with actual filters
140*e4050f96SAnna Dabrowska     */
141*e4050f96SAnna Dabrowska    public function test_addFiltersToSearch_with_filters()
142*e4050f96SAnna Dabrowska    {
143*e4050f96SAnna Dabrowska        $search = $this->createMock(\dokuwiki\plugin\struct\meta\Search::class);
144*e4050f96SAnna Dabrowska
145*e4050f96SAnna Dabrowska        // Track the calls to addFilter
146*e4050f96SAnna Dabrowska        $callCount = 0;
147*e4050f96SAnna Dabrowska        $expectedCalls = [
148*e4050f96SAnna Dabrowska            ['field1', 'value1', '=', 'AND'],
149*e4050f96SAnna Dabrowska            ['field2', '10', '>', 'AND']
150*e4050f96SAnna Dabrowska        ];
151*e4050f96SAnna Dabrowska
152*e4050f96SAnna Dabrowska        // Expect addFilter to be called twice (once for each filter line)
153*e4050f96SAnna Dabrowska        $search->expects($this->exactly(2))
154*e4050f96SAnna Dabrowska               ->method('addFilter')
155*e4050f96SAnna Dabrowska               ->willReturnCallback(function($colname, $value, $comp, $logic) use (&$callCount, $expectedCalls) {
156*e4050f96SAnna Dabrowska                   $this->assertEquals($expectedCalls[$callCount][0], $colname);
157*e4050f96SAnna Dabrowska                   $this->assertEquals($expectedCalls[$callCount][1], $value);
158*e4050f96SAnna Dabrowska                   $this->assertEquals($expectedCalls[$callCount][2], $comp);
159*e4050f96SAnna Dabrowska                   $this->assertEquals($expectedCalls[$callCount][3], $logic);
160*e4050f96SAnna Dabrowska                   $callCount++;
161*e4050f96SAnna Dabrowska               });
162*e4050f96SAnna Dabrowska
163*e4050f96SAnna Dabrowska        // Add filters
164*e4050f96SAnna Dabrowska        $filters = "field1 = value1\r\nfield2 > 10";
165*e4050f96SAnna Dabrowska        $this->callPrivateMethod('addFiltersToSearch', [&$search, $filters]);
166*e4050f96SAnna Dabrowska    }
167*e4050f96SAnna Dabrowska
168*e4050f96SAnna Dabrowska    /**
169*e4050f96SAnna Dabrowska     * Helper method to call private methods
170*e4050f96SAnna Dabrowska     */
171*e4050f96SAnna Dabrowska    private function callPrivateMethod($methodName, $args = [])
172*e4050f96SAnna Dabrowska    {
173*e4050f96SAnna Dabrowska        $reflection = new \ReflectionClass($this->action);
174*e4050f96SAnna Dabrowska        $method = $reflection->getMethod($methodName);
175*e4050f96SAnna Dabrowska        $method->setAccessible(true);
176*e4050f96SAnna Dabrowska        return $method->invokeArgs($this->action, $args);
177*e4050f96SAnna Dabrowska    }
178*e4050f96SAnna Dabrowska
179*e4050f96SAnna Dabrowska    /**
180*e4050f96SAnna Dabrowska     * Helper method to create mock Value objects
181*e4050f96SAnna Dabrowska     */
182*e4050f96SAnna Dabrowska    private function createMockValue($schema, $label, $rawValue)
183*e4050f96SAnna Dabrowska    {
184*e4050f96SAnna Dabrowska        $column = $this->createMock(Column::class);
185*e4050f96SAnna Dabrowska        $column->method('getTable')->willReturn($schema);
186*e4050f96SAnna Dabrowska        $column->method('getLabel')->willReturn($label);
187*e4050f96SAnna Dabrowska
188*e4050f96SAnna Dabrowska        $value = $this->createMock(Value::class);
189*e4050f96SAnna Dabrowska        $value->method('getColumn')->willReturn($column);
190*e4050f96SAnna Dabrowska        $value->method('getRawValue')->willReturn($rawValue);
191*e4050f96SAnna Dabrowska        $value->method('getDisplayValue')->willReturn($rawValue);
192*e4050f96SAnna Dabrowska
193*e4050f96SAnna Dabrowska        return $value;
194*e4050f96SAnna Dabrowska    }
195*e4050f96SAnna Dabrowska}
196