6
6
7
7
import datetime
8
8
from django .utils import timezone
9
-
9
+ from django . utils . html import escape , format_html
10
10
from django .core .exceptions import ValidationError
11
11
from django .test import TestCase , override_settings
12
12
from django .utils .safestring import SafeString
13
-
14
- from coldfront .core .allocation .models import Allocation , AllocationStatusChoice
13
+ from unittest . mock import patch
14
+ from coldfront .core .allocation .models import Allocation , AllocationStatusChoice , AllocationAttribute
15
15
from coldfront .core .project .models import Project
16
16
from coldfront .core .test_helpers .factories import (
17
17
AllocationFactory ,
18
18
AllocationStatusChoiceFactory ,
19
+ AllocationAttributeFactory ,
20
+ AllocationAttributeTypeFactory ,
21
+ AAttributeTypeFactory ,
22
+ AllocationAttributeUsageFactory ,
19
23
ProjectFactory ,
20
24
ResourceFactory ,
21
25
)
@@ -143,7 +147,6 @@ def test_status_is_active_and_start_date_equals_end_date_no_error(self):
143
147
144
148
class AllocationFuncOnExpireException (Exception ):
145
149
"""Custom exception for testing allocation expiration function in the AllocationModelSaveMethodTests class."""
146
-
147
150
pass
148
151
149
152
@@ -162,12 +165,10 @@ def get_dotted_path(func):
162
165
163
166
def count_invocations (* args , ** kwargs ):
164
167
count_invocations .invocation_count = getattr (count_invocations , "invocation_count" , 0 ) + 1
165
- pass
166
168
167
169
168
170
def count_invocations_negative (* args , ** kwargs ):
169
171
count_invocations_negative .invocation_count = getattr (count_invocations_negative , "invocation_count" , 0 ) - 1
170
- pass
171
172
172
173
173
174
def list_of_same_expire_funcs (func : callable , size = NUMBER_OF_INVOCATIONS ) -> list [str ]:
@@ -296,5 +297,127 @@ def test_multiple_new_allocations_are_in_database(self):
296
297
297
298
298
299
class AllocationModelExpiresInTests (TestCase ):
299
- # going to skip ths until I know how datetimes should be handled
300
- ...
300
+
301
+ mocked_today = datetime .date (2025 , 1 , 1 )
302
+ three_years_after_mocked_today = datetime .date (2028 , 1 , 1 )
303
+ four_years_after_mocked_today = datetime .date (2029 , 1 , 1 )
304
+
305
+ def test_end_date_is_today_returns_zero (self ):
306
+ """Test that the expires_in method returns 0 when the end date is today."""
307
+ allocation : Allocation = AllocationFactory (end_date = timezone .now ().date ())
308
+ self .assertEqual (allocation .expires_in , 0 )
309
+
310
+ def test_end_date_tomorrow_returns_one (self ):
311
+ """Test that the expires_in method returns 1 when the end date is tomorrow."""
312
+ tomorrow : datetime .date = (timezone .now () + datetime .timedelta (days = 1 )).date ()
313
+ allocation : Allocation = AllocationFactory (end_date = tomorrow )
314
+ self .assertEqual (allocation .expires_in , 1 )
315
+
316
+ def test_end_date_yesterday_returns_negative_one (self ):
317
+ """Test that the expires_in method returns -1 when the end date is yesterday."""
318
+ yesterday : datetime .date = (timezone .now () - datetime .timedelta (days = 1 )).date ()
319
+ allocation : Allocation = AllocationFactory (end_date = yesterday )
320
+ self .assertEqual (allocation .expires_in , - 1 )
321
+
322
+ def test_end_date_one_week_ago_returns_negative_seven (self ):
323
+ """Test that the expires_in method returns -7 when the end date is one week ago."""
324
+ days_in_a_week : int = 7
325
+ one_week_ago : datetime .date = (timezone .now () - datetime .timedelta (days = days_in_a_week )).date ()
326
+ allocation : Allocation = AllocationFactory (end_date = one_week_ago )
327
+ self .assertEqual (allocation .expires_in , - days_in_a_week )
328
+
329
+ def test_end_date_in_one_week_returns_seven (self ):
330
+ """Test that the expires_in method returns 7 when the end date is in one week."""
331
+ days_in_a_week : int = 7
332
+ one_week_from_now : datetime .date = (timezone .now () + datetime .timedelta (days = days_in_a_week )).date ()
333
+ allocation : Allocation = AllocationFactory (end_date = one_week_from_now )
334
+ self .assertEqual (allocation .expires_in , days_in_a_week )
335
+
336
+ def test_end_date_in_three_years_without_leap_day_returns_days_including_no_leap_day (self ):
337
+ """Test that the expires_in method returns the correct number of days in three years when those years did not have a leap year."""
338
+ days_in_three_years_excluding_leap_year = 365 * 3
339
+
340
+ with patch ("coldfront.core.allocation.models.datetime" ) as mock_datetime :
341
+ mock_datetime .date .today .return_value = self .mocked_today
342
+
343
+ allocation : Allocation = AllocationFactory (end_date = self .three_years_after_mocked_today )
344
+
345
+ self .assertEqual (allocation .expires_in , days_in_three_years_excluding_leap_year )
346
+
347
+ def test_end_date_in_four_years_returns_days_including_leap_day (self ):
348
+ """Test that the expires_in method accounts for the extra day of a leap year."""
349
+ days_in_four_years_including_leap_year = (365 * 4 ) + 1
350
+
351
+ with patch ("coldfront.core.allocation.models.datetime" ) as mock_datetime :
352
+ mock_datetime .date .today .return_value = self .mocked_today
353
+
354
+ allocation : Allocation = AllocationFactory (end_date = self .four_years_after_mocked_today )
355
+
356
+ self .assertEqual (allocation .expires_in , days_in_four_years_including_leap_year )
357
+
358
+
359
+
360
+ class AllocationModelGetInformationTests (TestCase ):
361
+
362
+ def test_no_allocation_attributes_returns_empty_string (self ):
363
+ """Test that the get_information method returns an empty string if there are no allocation attributes."""
364
+ allocation : Allocation = AllocationFactory ()
365
+ self .assertEqual (allocation .get_information , "" )
366
+
367
+ def test_attribute_value_is_not_a_number_returns_invalid_value_string (self ):
368
+ """Test that the get_information method returns an empty string if the only attribute has value not parsable to a number."""
369
+ allocation : Allocation = AllocationFactory ()
370
+ text_not_parsable_to_number = "this is not parsable to a number"
371
+ allocation_attribute : AllocationAttribute = AllocationAttributeFactory (allocation = allocation , value = text_not_parsable_to_number )
372
+ self .assertEqual (allocation .get_information , "" )
373
+
374
+ def test_attribute_value_is_zero_returns_100_percent_string (self ):
375
+ allocation : Allocation = AllocationFactory ()
376
+ allocation_attribute : AllocationAttribute = AllocationAttributeFactory (allocation = allocation , value = 0 )
377
+ allocation_attribute_usage = AllocationAttributeUsageFactory (allocation_attribute = allocation_attribute , value = 10 )
378
+
379
+ allocation_attribute_type_name : str = allocation_attribute .allocation_attribute_type .name
380
+ allocation_attribute_usage_value : float = float (allocation_attribute_usage .value )
381
+ allocation_attribute_value : str = allocation_attribute .value
382
+ expected_percent = 100
383
+
384
+ expected_information : SafeString = format_html (
385
+ "{}: {}/{} ({} %) <br>" ,
386
+ allocation_attribute_type_name ,
387
+ allocation_attribute_usage_value ,
388
+ allocation_attribute_value ,
389
+ expected_percent ,
390
+ )
391
+
392
+ self .assertEqual (allocation .get_information , expected_information )
393
+
394
+ def test_multiple_attributes_with_same_type_returns_combined_information (self ):
395
+ """Test that the get_information method returns combined information for multiple attributes."""
396
+ allocation : Allocation = AllocationFactory ()
397
+ allocation_attribute_type = AllocationAttributeTypeFactory ()
398
+
399
+ allocation_attribute_1 : AllocationAttribute = AllocationAttributeFactory (
400
+ allocation = allocation , allocation_attribute_type = allocation_attribute_type , value = 100
401
+ )
402
+ allocation_attribute_2 : AllocationAttribute = AllocationAttributeFactory (
403
+ allocation = allocation , allocation_attribute_type = allocation_attribute_type , value = 1000
404
+ )
405
+ allocation_attribute_usage_1 = AllocationAttributeUsageFactory (allocation_attribute = allocation_attribute_1 , value = 50 )
406
+ allocation_attribute_usage_2 = AllocationAttributeUsageFactory (allocation_attribute = allocation_attribute_2 , value = 500 )
407
+
408
+ percent_1 = round ( (float (allocation_attribute_usage_1 .value ) / float (allocation_attribute_1 .value )) * 10_000 ) / 100
409
+ percent_2 = round ( (float (allocation_attribute_usage_2 .value ) / float (allocation_attribute_2 .value )) * 10_000 ) / 100
410
+
411
+ expected_information : SafeString = format_html (
412
+ "{}: {}/{} ({} %) <br>{}: {}/{} ({} %) <br>" ,
413
+ allocation_attribute_type .name ,
414
+ float (allocation_attribute_usage_1 .value ),
415
+ allocation_attribute_1 .value ,
416
+ percent_1 ,
417
+ allocation_attribute_type .name ,
418
+ float (allocation_attribute_usage_2 .value ),
419
+ allocation_attribute_2 .value ,
420
+ percent_2 ,
421
+ )
422
+
423
+ self .assertEqual (allocation .get_information , expected_information )
0 commit comments