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
35namespace KPlato
36{
37
38void 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
61void 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
69void 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
133void ResourceModelTester::cleanupTestCase()
134{
135 delete m_project;
136}
137
138void 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
198void 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
277void 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
354QTEST_KDEMAIN_CORE( KPlato::ResourceModelTester )
355
356#include "ResourceModelTester.moc"
357