1 | /* This file is part of the KDE project |
2 | Copyright (C) 2009 Dag Andersen <danders@get2net.dk> |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library 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 GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | #include "ResourceModelTester.h" |
20 | |
21 | #include "kptcommand.h" |
22 | #include "kptcalendar.h" |
23 | #include "kptdatetime.h" |
24 | #include "kptresource.h" |
25 | #include "kptnode.h" |
26 | #include "kpttask.h" |
27 | #include "kptschedule.h" |
28 | #include "kptappointment.h" |
29 | |
30 | #include <QModelIndex> |
31 | |
32 | #include <qtest_kde.h> |
33 | #include <kdebug.h> |
34 | |
35 | namespace KPlato |
36 | { |
37 | |
38 | void ResourceModelTester::printDebug( long id ) const { |
39 | Project *p = m_project; |
40 | Resource *r = m_resource; |
41 | qDebug()<<"Debug info -------------------------------------" ; |
42 | qDebug()<<"project start time:" <<p->startTime().toString(); |
43 | qDebug()<<"project end time :" <<p->endTime().toString(); |
44 | |
45 | qDebug()<<"Resource start:" <<r->startTime( id ).toString(); |
46 | qDebug()<<"Resource end :" <<r->endTime( id ).toString(); |
47 | qDebug()<<"Appointments:" <<r->numAppointments( id )<<"(internal)" ; |
48 | foreach ( Appointment *a, r->appointments( id ) ) { |
49 | foreach ( const AppointmentInterval &i, a->intervals().map() ) { |
50 | qDebug()<<" " <<i.startTime().toString()<<"-" <<i.endTime().toString()<<";" <<i.load(); |
51 | } |
52 | } |
53 | qDebug()<<"Appointments:" <<r->numExternalAppointments()<<"(external)" ; |
54 | foreach ( Appointment *a, r->externalAppointmentList() ) { |
55 | foreach ( const AppointmentInterval &i, a->intervals().map() ) { |
56 | qDebug()<<" " <<i.startTime().toString()<<"-" <<i.endTime().toString()<<";" <<i.load(); |
57 | } |
58 | } |
59 | } |
60 | |
61 | void ResourceModelTester::printSchedulingLog( const ScheduleManager &sm ) const |
62 | { |
63 | qDebug()<<"Scheduling log ---------------------------------" ; |
64 | foreach ( const QString &s, sm.expected()->logMessages() ) { |
65 | qDebug()<<s; |
66 | } |
67 | } |
68 | |
69 | void ResourceModelTester::initTestCase() |
70 | { |
71 | m_project = new Project(); |
72 | m_project->setName( "P1" ); |
73 | m_project->setId( m_project->uniqueNodeId() ); |
74 | m_project->registerNodeId( m_project ); |
75 | DateTime targetstart = DateTime( QDate::currentDate(), QTime(0,0,0) ); |
76 | DateTime targetend = DateTime( targetstart.addDays( 3 ) ); |
77 | m_project->setConstraintStartTime( targetstart ); |
78 | m_project->setConstraintEndTime( targetend); |
79 | |
80 | // standard worktime defines 8 hour day as default |
81 | QVERIFY( m_project->standardWorktime() ); |
82 | QCOMPARE( m_project->standardWorktime()->day(), 8.0 ); |
83 | m_calendar = new Calendar( "Test" ); |
84 | m_calendar->setDefault( true ); |
85 | QTime t1( 9, 0, 0 ); |
86 | QTime t2 ( 17, 0, 0 ); |
87 | int length = t1.msecsTo( t2 ); |
88 | for ( int i=1; i <= 7; ++i ) { |
89 | CalendarDay *d = m_calendar->weekday( i ); |
90 | d->setState( CalendarDay::Working ); |
91 | d->addInterval( t1, length ); |
92 | } |
93 | m_project->addCalendar( m_calendar ); |
94 | |
95 | |
96 | ResourceGroup *g = new ResourceGroup(); |
97 | g->setName( "G1" ); |
98 | m_project->addResourceGroup( g ); |
99 | m_resource = new Resource(); |
100 | m_resource->setName( "R1" ); |
101 | m_resource->setCalendar( m_calendar ); |
102 | m_project->addResource( g, m_resource ); |
103 | |
104 | m_task = m_project->createTask(); |
105 | m_task->setName( "T1" ); |
106 | m_project->addTask( m_task, m_project ); |
107 | m_task->estimate()->setUnit( Duration::Unit_h ); |
108 | m_task->estimate()->setExpectedEstimate( 8.0 ); |
109 | m_task->estimate()->setType( Estimate::Type_Effort ); |
110 | |
111 | |
112 | ResourceGroupRequest *gr = new ResourceGroupRequest( g ); |
113 | gr->addResourceRequest( new ResourceRequest( m_resource, 100 ) ); |
114 | m_task->addRequest( gr ); |
115 | |
116 | m_model.setProject( m_project ); |
117 | |
118 | QModelIndex idx; |
119 | int rows = m_model.rowCount( idx ); |
120 | QCOMPARE( rows, 1 ); |
121 | idx = m_model.index( 0, 0, idx ); |
122 | QCOMPARE( g->name(), m_model.data( idx ).toString() ); |
123 | |
124 | rows = m_model.rowCount( idx ); |
125 | QCOMPARE( rows, 1 ); |
126 | idx = m_model.index( 0, 0, idx ); |
127 | QCOMPARE( m_resource->name(), m_model.data( idx ).toString() ); |
128 | |
129 | idx = m_model.parent( idx ); |
130 | QCOMPARE( g->name(), m_model.data( idx ).toString() ); |
131 | } |
132 | |
133 | void ResourceModelTester::cleanupTestCase() |
134 | { |
135 | delete m_project; |
136 | } |
137 | |
138 | void ResourceModelTester::internalAppointments() |
139 | { |
140 | ScheduleManager *sm = m_project->createScheduleManager( "Test Plan" ); |
141 | m_project->addScheduleManager( sm ); |
142 | sm->createSchedules(); |
143 | m_project->calculate( *sm ); |
144 | long id = sm->scheduleId(); |
145 | m_model.setScheduleManager( sm ); |
146 | |
147 | //printDebug( sm->scheduleId() ); |
148 | |
149 | QModelIndex idx; |
150 | // resource group |
151 | int rows = m_model.rowCount( idx ); |
152 | QCOMPARE( rows, 1 ); |
153 | QModelIndex gidx = m_model.index( 0, 0, idx ); |
154 | QVERIFY( gidx.isValid() ); |
155 | |
156 | // reosurce |
157 | rows = m_model.rowCount( gidx ); |
158 | QCOMPARE( rows, 1 ); |
159 | QModelIndex ridx = m_model.index( 0, 0, gidx ); |
160 | QCOMPARE( m_resource->name(), m_model.data( ridx ).toString() ); |
161 | |
162 | ridx = m_model.index( m_resource ); |
163 | QVERIFY( ridx.isValid() ); |
164 | |
165 | // appointment |
166 | rows = m_model.rowCount( ridx ); |
167 | QCOMPARE( rows, m_resource->numAppointments( id ) ); |
168 | QCOMPARE( rows, 1 ); |
169 | |
170 | QModelIndex aidx = m_model.index( 0, 0, ridx ); // first appointment |
171 | QVERIFY( aidx.isValid() ); |
172 | rows = m_model.rowCount( aidx ); // num intervals |
173 | QCOMPARE( rows, 1 ); |
174 | |
175 | // interval |
176 | QModelIndex iidx = m_model.index( 0, 0, aidx ); // first interval |
177 | QVERIFY( iidx.isValid() ); |
178 | rows = m_model.rowCount( iidx ); // intervals don't have children |
179 | QCOMPARE( rows, 0 ); |
180 | |
181 | // appointment |
182 | idx = m_model.parent( iidx ); |
183 | QCOMPARE( idx, aidx ); |
184 | // resource |
185 | idx = m_model.parent( aidx ); |
186 | QCOMPARE( idx, ridx ); |
187 | |
188 | // resource group |
189 | idx = m_model.parent( ridx ); |
190 | QCOMPARE( idx, gidx ); |
191 | |
192 | // top |
193 | idx = m_model.parent( gidx ); |
194 | QVERIFY( ! idx.isValid() ); |
195 | |
196 | } |
197 | |
198 | void ResourceModelTester::externalAppointments() |
199 | { |
200 | DateTime targetstart = m_project->constraintStartTime(); |
201 | DateTime targetend = m_project->constraintEndTime(); |
202 | Task *t = m_task; |
203 | Resource *r = m_resource; |
204 | |
205 | r->addExternalAppointment( "Ext-1" , "External project 1" , targetstart, targetstart.addDays( 1 ), 100 ); |
206 | r->addExternalAppointment( "Ext-1" , "External project 1" , targetend.addDays( -1 ), targetend, 100 ); |
207 | |
208 | ScheduleManager *sm = m_project->createScheduleManager( "Test Plan" ); |
209 | m_project->addScheduleManager( sm ); |
210 | sm->createSchedules(); |
211 | m_project->calculate( *sm ); |
212 | long id = sm->scheduleId(); |
213 | m_model.setScheduleManager( sm ); |
214 | //printSchedulingLog( *sm ); |
215 | //printDebug( sm->scheduleId() ); |
216 | |
217 | // resource group |
218 | QModelIndex idx; |
219 | int rows = m_model.rowCount( idx ); |
220 | QCOMPARE( rows, 1 ); |
221 | idx = m_model.index( 0, 0, idx ); |
222 | QVERIFY( idx.isValid() ); |
223 | QVERIFY( ! m_model.parent( idx ).isValid() ); |
224 | |
225 | // resource |
226 | rows = m_model.rowCount( idx ); |
227 | QCOMPARE( rows, 1 ); |
228 | QModelIndex ridx = m_model.index( 0, 0, idx ); |
229 | QCOMPARE( m_resource->name(), m_model.data( ridx ).toString() ); |
230 | QCOMPARE( ridx.parent(), idx ); |
231 | |
232 | ridx = m_model.index( m_resource ); |
233 | QVERIFY( ridx.isValid() ); |
234 | |
235 | // appointments |
236 | rows = m_model.rowCount( ridx ); |
237 | QCOMPARE( rows, m_resource->numAppointments( id ) + m_resource->numExternalAppointments() ); |
238 | QCOMPARE( rows, 2 ); // one internal, one external |
239 | |
240 | // internal appointment |
241 | QModelIndex aidx = m_model.index( 0, 0, ridx ); // first appointment (internal) |
242 | QVERIFY( aidx.isValid() ); |
243 | rows = m_model.rowCount( aidx ); // num intervals |
244 | QCOMPARE( rows, 1 ); |
245 | QCOMPARE( aidx.parent(), ridx ); |
246 | |
247 | QModelIndex iidx = m_model.index( 0, 0, aidx ); // first interval |
248 | QVERIFY( iidx.isValid() ); |
249 | rows = m_model.rowCount( iidx ); // intervals don't have children |
250 | QCOMPARE( rows, 0 ); |
251 | QCOMPARE( iidx.parent(), aidx ); |
252 | |
253 | // external appointment |
254 | aidx = m_model.index( 1, 0, ridx ); // second appointment (external) |
255 | QVERIFY( aidx.isValid() ); |
256 | rows = m_model.rowCount( aidx ); // num intervals |
257 | QCOMPARE( rows, 2 ); |
258 | QCOMPARE( aidx.parent(), ridx ); |
259 | |
260 | iidx = m_model.index( 0, 0, aidx ); // first interval |
261 | QVERIFY( iidx.isValid() ); |
262 | rows = m_model.rowCount( iidx ); // intervals don't have children |
263 | QCOMPARE( rows, 0 ); |
264 | QCOMPARE( iidx.parent(), aidx ); |
265 | |
266 | iidx = m_model.index( 1, 0, aidx ); // second interval |
267 | QVERIFY( iidx.isValid() ); |
268 | rows = m_model.rowCount( iidx ); // intervals don't have children |
269 | QCOMPARE( rows, 0 ); |
270 | QCOMPARE( iidx.parent(), aidx ); |
271 | |
272 | QCOMPARE( t->startTime(), m_calendar->firstAvailableAfter( targetstart + Duration( 1, 0, 0 ), t->endTime() ) ); |
273 | QCOMPARE( t->endTime(), t->startTime() + Duration( 0, 8, 0 ) ); |
274 | |
275 | } |
276 | |
277 | void ResourceModelTester::externalOverbook() |
278 | { |
279 | DateTime targetstart = m_project->constraintStartTime(); |
280 | DateTime targetend = m_project->constraintEndTime(); |
281 | Task *t = m_task; |
282 | Resource *r = m_resource; |
283 | |
284 | r->addExternalAppointment( "Ext-1" , "External project 1" , targetstart, targetstart.addDays( 1 ), 100 ); |
285 | r->addExternalAppointment( "Ext-1" , "External project 1" , targetend.addDays( -1 ), targetend, 100 ); |
286 | |
287 | ScheduleManager *sm = m_project->createScheduleManager( "Test Plan" ); |
288 | m_project->addScheduleManager( sm ); |
289 | sm->setAllowOverbooking( true ); |
290 | sm->createSchedules(); |
291 | m_project->calculate( *sm ); |
292 | long id = sm->scheduleId(); |
293 | m_model.setScheduleManager( sm ); |
294 | //printSchedulingLog( *sm ); |
295 | //printDebug( id ); |
296 | |
297 | // resource group |
298 | QModelIndex idx; |
299 | int rows = m_model.rowCount( idx ); |
300 | QCOMPARE( rows, 1 ); |
301 | idx = m_model.index( 0, 0, idx ); |
302 | QVERIFY( idx.isValid() ); |
303 | |
304 | // resource |
305 | rows = m_model.rowCount( idx ); |
306 | QCOMPARE( rows, 1 ); |
307 | idx = m_model.index( 0, 0, idx ); |
308 | QCOMPARE( m_resource->name(), m_model.data( idx ).toString() ); |
309 | |
310 | idx = m_model.index( m_resource ); |
311 | QVERIFY( idx.isValid() ); |
312 | |
313 | // appointments |
314 | rows = m_model.rowCount( idx ); |
315 | QCOMPARE( rows, m_resource->numAppointments( id ) + m_resource->numExternalAppointments() ); |
316 | QCOMPARE( rows, 2 ); // one internal, one external |
317 | |
318 | // internal appointment |
319 | QModelIndex aidx = m_model.index( 0, 0, idx ); // first appointment (internal) |
320 | QVERIFY( aidx.isValid() ); |
321 | rows = m_model.rowCount( aidx ); // num intervals |
322 | QCOMPARE( rows, 1 ); |
323 | |
324 | QModelIndex iidx = m_model.index( 0, 0, aidx ); // first interval |
325 | QVERIFY( iidx.isValid() ); |
326 | rows = m_model.rowCount( iidx ); // intervals don't have children |
327 | QCOMPARE( rows, 0 ); |
328 | |
329 | // external appointment |
330 | aidx = m_model.index( 1, 0, idx ); // second appointment (external) |
331 | QVERIFY( aidx.isValid() ); |
332 | rows = m_model.rowCount( aidx ); // num intervals |
333 | QCOMPARE( rows, 2 ); |
334 | |
335 | iidx = m_model.index( 0, 0, aidx ); // first interval |
336 | QVERIFY( iidx.isValid() ); |
337 | rows = m_model.rowCount( iidx ); // intervals don't have children |
338 | QCOMPARE( rows, 0 ); |
339 | |
340 | iidx = m_model.index( 1, 0, aidx ); // second interval |
341 | QVERIFY( iidx.isValid() ); |
342 | rows = m_model.rowCount( iidx ); // intervals don't have children |
343 | QCOMPARE( rows, 0 ); |
344 | |
345 | |
346 | QCOMPARE( t->startTime(), m_calendar->firstAvailableAfter( targetstart, t->endTime() ) ); |
347 | QCOMPARE( t->endTime(), t->startTime() + Duration( 0, 8, 0 ) ); |
348 | |
349 | } |
350 | |
351 | |
352 | } //namespace KPlato |
353 | |
354 | QTEST_KDEMAIN_CORE( KPlato::ResourceModelTester ) |
355 | |
356 | #include "ResourceModelTester.moc" |
357 | |