Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.89% covered (warning)
86.89%
53 / 61
84.21% covered (warning)
84.21%
16 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
CsvItem
86.89% covered (warning)
86.89%
53 / 61
84.21% covered (warning)
84.21%
16 / 19
41.26
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getQuestion
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isShuffle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMinChoices
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMaxChoices
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLanguage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getChoices
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCorrectChoices
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getMetadata
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMaxScore
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
6.22
 isMatchCorrectResponse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isMapResponse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isNoneResponse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 hasAtLeastOneCorrectAnswer
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMaxTotalScore
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getHigherScore
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 getHigherPossibleTotalScore
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 getScoreCount
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/*
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2021 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 */
20
21declare(strict_types=1);
22
23namespace oat\taoQtiItem\model\import;
24
25class CsvItem implements ItemInterface
26{
27    /** @var string */
28    private $name;
29
30    /** @var string */
31    private $question;
32
33    /** @var bool */
34    private $shuffle;
35
36    /** @var int */
37    private $minChoices;
38
39    /** @var int */
40    private $maxChoices;
41
42    /** @var string */
43    private $language;
44
45    /** @var ParsedChoice[] */
46    private $choices;
47
48    /** @var ParsedMetadatum[] */
49    private $metadata;
50
51    public function __construct(
52        string $name,
53        string $question,
54        bool $shuffle,
55        int $minChoices,
56        int $maxChoices,
57        string $language,
58        array $choices,
59        array $metadata
60    ) {
61        $this->name = $name;
62        $this->question = $question;
63        $this->shuffle = $shuffle;
64        $this->minChoices = $minChoices;
65        $this->maxChoices = $maxChoices;
66        $this->language = $language;
67        $this->choices = $choices;
68        $this->metadata = $metadata;
69    }
70
71    public function getName(): string
72    {
73        return $this->name;
74    }
75
76    public function getQuestion(): string
77    {
78        return $this->question;
79    }
80
81    public function isShuffle(): bool
82    {
83        return $this->shuffle;
84    }
85
86    public function getMinChoices(): int
87    {
88        return $this->minChoices;
89    }
90
91    public function getMaxChoices(): int
92    {
93        return $this->maxChoices;
94    }
95
96    public function getLanguage(): string
97    {
98        return $this->language;
99    }
100
101    /**
102     * @return ParsedChoice[]
103     */
104    public function getChoices(): array
105    {
106        return $this->choices;
107    }
108
109    public function getCorrectChoices(): array
110    {
111        $choices = [];
112
113        foreach ($this->choices as $choice) {
114            if ($choice->isCorrect()) {
115                $choices[] = $choice;
116            }
117        }
118
119        return $choices;
120    }
121
122    /**
123     * @return ParsedMetadatum[]
124     */
125    public function getMetadata(): array
126    {
127        return $this->metadata;
128    }
129
130    public function getMaxScore(): float
131    {
132        if ($this->isMatchCorrectResponse()) {
133            return 1;
134        }
135
136        if ($this->isNoneResponse()) {
137            return 0;
138        }
139
140        if ($this->maxChoices === 0) {
141            return $this->getMaxTotalScore();
142        }
143
144        if ($this->maxChoices === 1) {
145            return $this->getHigherScore();
146        }
147
148        if ($this->maxChoices > 1) {
149            return $this->getHigherPossibleTotalScore();
150        }
151
152        return 0;
153    }
154
155    public function isMatchCorrectResponse(): bool
156    {
157        return $this->getScoreCount() === 0 && $this->hasAtLeastOneCorrectAnswer();
158    }
159
160    public function isMapResponse(): bool
161    {
162        return $this->getScoreCount() > 0;
163    }
164
165    public function isNoneResponse(): bool
166    {
167        return $this->getScoreCount() === 0 && !$this->hasAtLeastOneCorrectAnswer();
168    }
169
170    private function hasAtLeastOneCorrectAnswer(): bool
171    {
172        return count($this->getCorrectChoices()) > 0;
173    }
174
175    private function getMaxTotalScore(): float
176    {
177        $totalScore = 0;
178
179        foreach ($this->choices as $choice) {
180            if ($choice->getChoiceScore() > 0) {
181                $totalScore += $choice->getChoiceScore();
182            }
183        }
184
185        return $totalScore;
186    }
187
188    private function getHigherScore(): float
189    {
190        $scores = [];
191
192        foreach ($this->choices as $choice) {
193            if ($choice->getChoiceScore() > 0) {
194                $scores[$choice->getChoiceScore()] = $choice->getChoiceScore();
195            }
196        }
197
198        return count($scores) ? max($scores) : 0;
199    }
200
201    private function getHigherPossibleTotalScore(): float
202    {
203        $scores = [];
204
205        foreach ($this->choices as $choice) {
206            if ($choice->getChoiceScore() > 0) {
207                $scores[] = $choice->getChoiceScore();
208            }
209        }
210
211        rsort($scores);
212
213        $totalScore = 0;
214
215        for ($i = 0; $i < $this->maxChoices; $i++) {
216            $totalScore += current($scores);
217
218            next($scores);
219        }
220
221        return $totalScore;
222    }
223
224    private function getScoreCount(): int
225    {
226        $totalScores = 0;
227
228        foreach ($this->choices as $choice) {
229            if ($choice->getChoiceScore() > 0) {
230                $totalScores++;
231            }
232        }
233
234        return $totalScores;
235    }
236}