Skip to content

Commit d999622

Browse files
committed
add some service tests
Signed-off-by: dartcafe <github@dartcafe.de>
1 parent 34e4ae7 commit d999622

File tree

3 files changed

+608
-0
lines changed

3 files changed

+608
-0
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2026 Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Polls\Tests\Unit\Service;
10+
11+
use OCA\Polls\Db\Option;
12+
use OCA\Polls\Db\OptionMapper;
13+
use OCA\Polls\Db\Poll;
14+
use OCA\Polls\Db\PollMapper;
15+
use OCA\Polls\Exceptions\InsufficientAttributesException;
16+
use OCA\Polls\Model\SimpleOption;
17+
use OCA\Polls\Service\OptionService;
18+
use OCA\Polls\Tests\Unit\UnitTestCase;
19+
use OCP\ISession;
20+
use OCP\Server;
21+
22+
class OptionServiceTest extends UnitTestCase {
23+
private OptionService $optionService;
24+
private OptionMapper $optionMapper;
25+
private PollMapper $pollMapper;
26+
private ISession $session;
27+
28+
private Poll $textPoll;
29+
private Poll $datePoll;
30+
private Option $textOption;
31+
32+
protected function setUp(): void {
33+
parent::setUp();
34+
$this->session = Server::get(ISession::class);
35+
$this->session->set('ncPollsUserId', 'admin');
36+
37+
$this->optionService = Server::get(OptionService::class);
38+
$this->optionMapper = Server::get(OptionMapper::class);
39+
$this->pollMapper = Server::get(PollMapper::class);
40+
41+
// Text poll owned by admin, private, open
42+
$poll = $this->fm->instance('OCA\Polls\Db\Poll');
43+
$poll->setOwner('admin');
44+
$poll->setType(Poll::TYPE_TEXT);
45+
$poll->setAccess(Poll::ACCESS_PRIVATE);
46+
$poll->setExpire(0);
47+
$this->textPoll = $this->pollMapper->insert($poll);
48+
49+
// Date poll owned by admin, private, open
50+
$datePoll = $this->fm->instance('OCA\Polls\Db\Poll');
51+
$datePoll->setOwner('admin');
52+
$datePoll->setType(Poll::TYPE_DATE);
53+
$datePoll->setAccess(Poll::ACCESS_PRIVATE);
54+
$datePoll->setExpire(0);
55+
$this->datePoll = $this->pollMapper->insert($datePoll);
56+
57+
// Pre-existing text option for update/delete/confirm/reorder tests
58+
$this->textOption = $this->optionService->add(
59+
$this->textPoll->getId(),
60+
(new SimpleOption())->setText('Initial option')
61+
);
62+
}
63+
64+
protected function tearDown(): void {
65+
parent::tearDown();
66+
// Options are deleted when their poll is deleted
67+
try {
68+
$this->pollMapper->delete($this->textPoll);
69+
} catch (\Exception $e) {
70+
}
71+
try {
72+
$this->pollMapper->delete($this->datePoll);
73+
} catch (\Exception $e) {
74+
}
75+
}
76+
77+
// --- add ---
78+
79+
public function testAddTextOptionToTextPoll(): void {
80+
$option = $this->optionService->add(
81+
$this->textPoll->getId(),
82+
(new SimpleOption())->setText('New Option')
83+
);
84+
$this->assertInstanceOf(Option::class, $option);
85+
$this->assertSame('New Option', $option->getPollOptionText());
86+
$this->assertSame($this->textPoll->getId(), $option->getPollId());
87+
}
88+
89+
public function testAddDateOptionToDatePoll(): void {
90+
$timestamp = strtotime('2027-06-15 12:00:00 UTC');
91+
$option = $this->optionService->add(
92+
$this->datePoll->getId(),
93+
(new SimpleOption())->setDateTime($timestamp)
94+
);
95+
$this->assertInstanceOf(Option::class, $option);
96+
$this->assertSame($this->datePoll->getId(), $option->getPollId());
97+
$this->assertSame($timestamp, $option->getTimestamp());
98+
}
99+
100+
// --- addBulk ---
101+
102+
public function testAddBulkAddsMultipleOptions(): void {
103+
$bulkText = implode(PHP_EOL, ['Bulk A', 'Bulk B', 'Bulk C']);
104+
$options = $this->optionService->addBulk($this->textPoll->getId(), $bulkText);
105+
// setUp created 1 option; addBulk adds 3 more → at least 4
106+
$this->assertGreaterThanOrEqual(4, count($options));
107+
}
108+
109+
public function testAddBulkDeduplicates(): void {
110+
$countBefore = count($this->optionService->list($this->textPoll->getId()));
111+
$bulkText = implode(PHP_EOL, ['Unique One', 'Unique One']);
112+
$this->optionService->addBulk($this->textPoll->getId(), $bulkText);
113+
$countAfter = count($this->optionService->list($this->textPoll->getId()));
114+
// array_unique in addBulk means only 1 new option added despite 2 lines
115+
$this->assertSame($countBefore + 1, $countAfter);
116+
}
117+
118+
// --- list ---
119+
120+
public function testListReturnsOptionsForPoll(): void {
121+
$options = $this->optionService->list($this->textPoll->getId());
122+
$this->assertNotEmpty($options);
123+
foreach ($options as $option) {
124+
$this->assertSame($this->textPoll->getId(), $option->getPollId());
125+
}
126+
}
127+
128+
public function testListReturnsEmptyArrayForPollWithNoOptions(): void {
129+
$options = $this->optionService->list($this->datePoll->getId());
130+
$this->assertIsArray($options);
131+
$this->assertEmpty($options);
132+
}
133+
134+
// --- update ---
135+
136+
public function testUpdateTextOptionChangesText(): void {
137+
$updated = $this->optionService->update($this->textOption->getId(), 'Updated Text');
138+
$this->assertSame('Updated Text', $updated->getPollOptionText());
139+
}
140+
141+
public function testUpdateTextOptionThrowsOnEmptyText(): void {
142+
$this->expectException(InsufficientAttributesException::class);
143+
$this->optionService->update($this->textOption->getId(), '');
144+
}
145+
146+
// --- delete / restore ---
147+
148+
public function testDeleteSetsDeletedTimestamp(): void {
149+
$deleted = $this->optionService->delete($this->textOption->getId());
150+
$this->assertGreaterThan(0, $deleted->getDeleted());
151+
}
152+
153+
public function testRestoreClearsDeletedTimestamp(): void {
154+
$this->optionService->delete($this->textOption->getId());
155+
$restored = $this->optionService->delete($this->textOption->getId(), true);
156+
$this->assertSame(0, $restored->getDeleted());
157+
}
158+
159+
// --- confirm ---
160+
161+
public function testConfirmOptionOnExpiredPoll(): void {
162+
// Poll must be expired for confirm permission
163+
$this->textPoll->setExpire(time() - 3600);
164+
$this->pollMapper->update($this->textPoll);
165+
166+
$confirmed = $this->optionService->confirm($this->textOption->getId());
167+
$this->assertGreaterThan(0, $confirmed->getConfirmed());
168+
169+
// Restore: re-open the poll for tearDown
170+
$this->textPoll->setExpire(0);
171+
$this->pollMapper->update($this->textPoll);
172+
}
173+
174+
public function testConfirmTogglesConfirmation(): void {
175+
$this->textPoll->setExpire(time() - 3600);
176+
$this->pollMapper->update($this->textPoll);
177+
178+
$this->optionService->confirm($this->textOption->getId()); // confirm
179+
$unconfirmed = $this->optionService->confirm($this->textOption->getId()); // toggle back
180+
$this->assertSame(0, $unconfirmed->getConfirmed());
181+
182+
$this->textPoll->setExpire(0);
183+
$this->pollMapper->update($this->textPoll);
184+
}
185+
186+
// --- reorder ---
187+
188+
public function testReorderChangesOptionOrder(): void {
189+
$second = $this->optionService->add(
190+
$this->textPoll->getId(),
191+
(new SimpleOption())->setText('Second Option')
192+
);
193+
194+
// Swap order: second first, initial second
195+
$reordered = $this->optionService->reorder($this->textPoll->getId(), [
196+
['id' => $second->getId()],
197+
['id' => $this->textOption->getId()],
198+
]);
199+
200+
$this->assertCount(2, $reordered);
201+
$orderById = [];
202+
foreach ($reordered as $opt) {
203+
$orderById[$opt->getId()] = $opt->getOrder();
204+
}
205+
$this->assertSame(1, $orderById[$second->getId()]);
206+
$this->assertSame(2, $orderById[$this->textOption->getId()]);
207+
}
208+
}

0 commit comments

Comments
 (0)