GeneralManager 0.3.2__tar.gz → 0.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. {generalmanager-0.3.2 → generalmanager-0.4.1}/GeneralManager.egg-info/PKG-INFO +1 -1
  2. {generalmanager-0.3.2 → generalmanager-0.4.1}/GeneralManager.egg-info/SOURCES.txt +3 -1
  3. {generalmanager-0.3.2 → generalmanager-0.4.1}/PKG-INFO +1 -1
  4. {generalmanager-0.3.2 → generalmanager-0.4.1}/pyproject.toml +1 -1
  5. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/factory/__init__.py +1 -1
  6. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/factory/factories.py +71 -54
  7. generalmanager-0.4.1/src/general_manager/factory/factoryMethods.py +109 -0
  8. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/measurement/measurement.py +8 -0
  9. generalmanager-0.4.1/tests/test_factories.py +350 -0
  10. generalmanager-0.4.1/tests/test_factoryMethods.py +228 -0
  11. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_noneToZero.py +2 -2
  12. generalmanager-0.3.2/src/general_manager/factory/lazy_methods.py +0 -38
  13. {generalmanager-0.3.2 → generalmanager-0.4.1}/GeneralManager.egg-info/dependency_links.txt +0 -0
  14. {generalmanager-0.3.2 → generalmanager-0.4.1}/GeneralManager.egg-info/requires.txt +0 -0
  15. {generalmanager-0.3.2 → generalmanager-0.4.1}/GeneralManager.egg-info/top_level.txt +0 -0
  16. {generalmanager-0.3.2 → generalmanager-0.4.1}/LICENSE +0 -0
  17. {generalmanager-0.3.2 → generalmanager-0.4.1}/README.md +0 -0
  18. {generalmanager-0.3.2 → generalmanager-0.4.1}/setup.cfg +0 -0
  19. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/__init__.py +0 -0
  20. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/api/graphql.py +0 -0
  21. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/api/mutation.py +0 -0
  22. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/api/property.py +0 -0
  23. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/apps.py +0 -0
  24. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/__init__.py +0 -0
  25. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/argsToKwargs.py +0 -0
  26. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/filterParser.py +0 -0
  27. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/jsonEncoder.py +0 -0
  28. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/makeCacheKey.py +0 -0
  29. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/noneToZero.py +0 -0
  30. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/auxiliary/pathMapping.py +0 -0
  31. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/cache/cacheDecorator.py +0 -0
  32. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/cache/cacheTracker.py +0 -0
  33. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/cache/dependencyIndex.py +0 -0
  34. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/cache/modelDependencyCollector.py +0 -0
  35. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/cache/signals.py +0 -0
  36. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/interface/__init__.py +0 -0
  37. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/interface/baseInterface.py +0 -0
  38. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/interface/calculationInterface.py +0 -0
  39. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/interface/databaseInterface.py +0 -0
  40. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/manager/__init__.py +0 -0
  41. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/manager/generalManager.py +0 -0
  42. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/manager/groupManager.py +0 -0
  43. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/manager/input.py +0 -0
  44. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/manager/meta.py +0 -0
  45. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/measurement/__init__.py +0 -0
  46. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/measurement/measurementField.py +0 -0
  47. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/__init__.py +0 -0
  48. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/basePermission.py +0 -0
  49. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/fileBasedPermission.py +0 -0
  50. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/managerBasedPermission.py +0 -0
  51. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/permissionChecks.py +0 -0
  52. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/permission/permissionDataManager.py +0 -0
  53. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/rule/__init__.py +0 -0
  54. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/rule/handler.py +0 -0
  55. {generalmanager-0.3.2 → generalmanager-0.4.1}/src/general_manager/rule/rule.py +0 -0
  56. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_argsToKwargs.py +0 -0
  57. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_basePermission.py +0 -0
  58. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_cacheDecorator.py +0 -0
  59. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_cacheTracker.py +0 -0
  60. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_dependencyIndex.py +0 -0
  61. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_filterParser.py +0 -0
  62. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_graph_ql.py +0 -0
  63. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_input.py +0 -0
  64. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_jsonEncoder.py +0 -0
  65. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_makeCacheKey.py +0 -0
  66. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_managerBasedPermission.py +0 -0
  67. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_measurement.py +0 -0
  68. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_measurement_field.py +0 -0
  69. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_modelDependencyCollector.py +0 -0
  70. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_rule_handler.py +0 -0
  71. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_rules.py +0 -0
  72. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_settings.py +0 -0
  73. {generalmanager-0.3.2 → generalmanager-0.4.1}/tests/test_signals.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.3.2
3
+ Version: 0.4.1
4
4
  Summary: Kurzbeschreibung deines Pakets
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: Non-Commercial MIT License
@@ -25,7 +25,7 @@ src/general_manager/cache/modelDependencyCollector.py
25
25
  src/general_manager/cache/signals.py
26
26
  src/general_manager/factory/__init__.py
27
27
  src/general_manager/factory/factories.py
28
- src/general_manager/factory/lazy_methods.py
28
+ src/general_manager/factory/factoryMethods.py
29
29
  src/general_manager/interface/__init__.py
30
30
  src/general_manager/interface/baseInterface.py
31
31
  src/general_manager/interface/calculationInterface.py
@@ -52,6 +52,8 @@ tests/test_basePermission.py
52
52
  tests/test_cacheDecorator.py
53
53
  tests/test_cacheTracker.py
54
54
  tests/test_dependencyIndex.py
55
+ tests/test_factories.py
56
+ tests/test_factoryMethods.py
55
57
  tests/test_filterParser.py
56
58
  tests/test_graph_ql.py
57
59
  tests/test_input.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.3.2
3
+ Version: 0.4.1
4
4
  Summary: Kurzbeschreibung deines Pakets
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: Non-Commercial MIT License
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "GeneralManager"
10
- version = "0.3.2"
10
+ version = "0.4.1"
11
11
  description = "Kurzbeschreibung deines Pakets"
12
12
  readme = "README.md"
13
13
  authors = [
@@ -1,4 +1,4 @@
1
- from .lazy_methods import (
1
+ from .factoryMethods import (
2
2
  LazyMeasurement,
3
3
  LazyDeltaDate,
4
4
  LazyProjectName,
@@ -1,17 +1,16 @@
1
1
  from __future__ import annotations
2
2
  from typing import TYPE_CHECKING, Type, Callable, Union, Any, TypeVar, Literal, cast
3
- from factory.declarations import LazyFunction, LazyAttribute, LazyAttributeSequence
3
+ from factory.declarations import LazyFunction
4
4
  from factory.faker import Faker
5
5
  import exrex # type: ignore
6
6
  from django.db import models
7
7
  from django.core.validators import RegexValidator
8
8
  from factory.django import DjangoModelFactory
9
- from django.utils import timezone
10
9
  import random
11
10
  from decimal import Decimal
12
11
  from general_manager.measurement.measurement import Measurement
13
12
  from general_manager.measurement.measurementField import MeasurementField
14
- from datetime import date, datetime, time
13
+ from datetime import date, datetime, time, timezone
15
14
 
16
15
  if TYPE_CHECKING:
17
16
  from general_manager.interface.databaseInterface import (
@@ -33,7 +32,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
33
32
  ) = None
34
33
 
35
34
  @classmethod
36
- def _generate( # type: ignore
35
+ def _generate(
37
36
  cls, strategy: Literal["build", "create"], params: dict[str, Any]
38
37
  ) -> models.Model | list[models.Model]:
39
38
  cls._original_params = params
@@ -64,7 +63,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
64
63
  continue # Skip fields that are already set
65
64
  if isinstance(field, models.AutoField) or field.auto_created:
66
65
  continue # Skip auto fields
67
- params[field.name] = get_field_value(field)
66
+ params[field.name] = getFieldValue(field)
68
67
 
69
68
  obj: list[models.Model] | models.Model = super()._generate(strategy, params)
70
69
  if isinstance(obj, list):
@@ -84,7 +83,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
84
83
  if field.name in attrs:
85
84
  m2m_values = attrs[field.name]
86
85
  else:
87
- m2m_values = get_m2m_field_value(field)
86
+ m2m_values = getManyToManyFieldValue(field)
88
87
  if m2m_values:
89
88
  getattr(obj, field.name).set(m2m_values)
90
89
 
@@ -98,7 +97,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
98
97
  return kwargs
99
98
 
100
99
  @classmethod
101
- def _create( # type: ignore
100
+ def _create(
102
101
  cls, model_class: Type[models.Model], *args: list[Any], **kwargs: dict[str, Any]
103
102
  ) -> models.Model | list[models.Model]:
104
103
  kwargs = cls._adjust_kwargs(**kwargs)
@@ -107,7 +106,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
107
106
  return cls._modelCreation(model_class, **kwargs)
108
107
 
109
108
  @classmethod
110
- def _build( # type: ignore
109
+ def _build(
111
110
  cls, model_class: Type[models.Model], *args: list[Any], **kwargs: dict[str, Any]
112
111
  ) -> models.Model | list[models.Model]:
113
112
  kwargs = cls._adjust_kwargs(**kwargs)
@@ -157,7 +156,7 @@ class AutoFactory(DjangoModelFactory[modelsModel]):
157
156
  return created_objects
158
157
 
159
158
 
160
- def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) -> object:
159
+ def getFieldValue(field: models.Field[Any, Any] | models.ForeignObjectRel) -> object:
161
160
  """
162
161
  Returns a suitable value for a given Django model field.
163
162
  """
@@ -166,22 +165,12 @@ def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) ->
166
165
  return None
167
166
 
168
167
  if isinstance(field, MeasurementField):
169
- base_unit = field.base_unit
170
- value = Decimal(str(random.uniform(0, 10_000))[:10])
171
- return LazyFunction(lambda: Measurement(value, base_unit))
172
- elif isinstance(field, models.CharField):
173
- max_length = field.max_length or 100
174
- # Check for RegexValidator
175
- regex = None
176
- for validator in field.validators:
177
- if isinstance(validator, RegexValidator):
178
- regex = getattr(validator.regex, "pattern", None)
179
- break
180
- if regex:
181
- # Use exrex to generate a string matching the regex
182
- return LazyFunction(lambda: exrex.getone(regex)) # type: ignore
183
- else:
184
- return cast(str, Faker("text", max_nb_chars=max_length))
168
+
169
+ def _measurement():
170
+ value = Decimal(random.randrange(0, 10_000_000)) / Decimal("100") # two dp
171
+ return Measurement(value, field.base_unit)
172
+
173
+ return LazyFunction(_measurement)
185
174
  elif isinstance(field, models.TextField):
186
175
  return cast(str, Faker("paragraph"))
187
176
  elif isinstance(field, models.IntegerField):
@@ -201,8 +190,6 @@ def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) ->
201
190
  )
202
191
  elif isinstance(field, models.FloatField):
203
192
  return cast(float, Faker("pyfloat", positive=True))
204
- elif isinstance(field, models.DateField):
205
- return cast(date, Faker("date_between", start_date="-1y", end_date="today"))
206
193
  elif isinstance(field, models.DateTimeField):
207
194
  return cast(
208
195
  datetime,
@@ -213,10 +200,11 @@ def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) ->
213
200
  tzinfo=timezone.utc,
214
201
  ),
215
202
  )
203
+ elif isinstance(field, models.DateField):
204
+ return cast(date, Faker("date_between", start_date="-1y", end_date="today"))
216
205
  elif isinstance(field, models.BooleanField):
217
206
  return cast(bool, Faker("pybool"))
218
- elif isinstance(field, models.ForeignKey):
219
- # Create or get an instance of the related model
207
+ elif isinstance(field, models.OneToOneField):
220
208
  if hasattr(field.related_model, "_general_manager_class"):
221
209
  related_factory = field.related_model._general_manager_class.Factory
222
210
  return related_factory()
@@ -229,11 +217,19 @@ def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) ->
229
217
  raise ValueError(
230
218
  f"No factory found for {field.related_model.__name__} and no instances found"
231
219
  )
232
- elif isinstance(field, models.OneToOneField):
233
- # Similar to ForeignKey
220
+ elif isinstance(field, models.ForeignKey):
221
+ # Create or get an instance of the related model
234
222
  if hasattr(field.related_model, "_general_manager_class"):
223
+ create_a_new_instance = random.choice([True, True, False])
224
+ if not create_a_new_instance:
225
+ existing_instances = list(field.related_model.objects.all())
226
+ if existing_instances:
227
+ # Pick a random existing instance
228
+ return LazyFunction(lambda: random.choice(existing_instances))
229
+
235
230
  related_factory = field.related_model._general_manager_class.Factory
236
231
  return related_factory()
232
+
237
233
  else:
238
234
  # If no factory exists, pick a random existing instance
239
235
  related_instances = list(field.related_model.objects.all())
@@ -253,35 +249,56 @@ def get_field_value(field: models.Field[Any, Any] | models.ForeignObjectRel) ->
253
249
  return cast(str, Faker("uuid4"))
254
250
  elif isinstance(field, models.DurationField):
255
251
  return cast(time, Faker("time_delta"))
252
+ elif isinstance(field, models.CharField):
253
+ max_length = field.max_length or 100
254
+ # Check for RegexValidator
255
+ regex = None
256
+ for validator in field.validators:
257
+ if isinstance(validator, RegexValidator):
258
+ regex = getattr(validator.regex, "pattern", None)
259
+ break
260
+ if regex:
261
+ # Use exrex to generate a string matching the regex
262
+ return LazyFunction(lambda: exrex.getone(regex)) # type: ignore
263
+ else:
264
+ return cast(str, Faker("text", max_nb_chars=max_length))
256
265
  else:
257
266
  return None # For unsupported field types
258
267
 
259
268
 
260
- def get_m2m_field_value(field: models.ManyToManyField[Any, Any]) -> list[models.Model]:
269
+ def getManyToManyFieldValue(
270
+ field: models.ManyToManyField,
271
+ ) -> list[models.Model]:
261
272
  """
262
273
  Returns a list of instances for a ManyToMany field.
263
274
  """
264
- related_factory = globals().get(f"{field.related_model.__name__}Factory")
265
- existing_instances = list(field.related_model.objects.all())
275
+ related_factory = None
276
+ related_instances = list(field.related_model.objects.all())
277
+ if hasattr(field.related_model, "_general_manager_class"):
278
+ related_factory = field.related_model._general_manager_class.Factory
266
279
 
267
- if related_factory:
268
- # Use existing instances if available, otherwise create new ones
269
- if existing_instances:
270
- max_instances = len(existing_instances)
271
- num_instances = random.randint(0, min(max_instances, 15))
272
- return random.sample(existing_instances, num_instances)
273
- else:
274
- # No existing instances, create a few
275
- num_to_create = random.randint(1, 3)
276
- new_instances = [related_factory() for _ in range(num_to_create)]
277
- return new_instances
280
+ min_required = 0 if field.blank else 1
281
+ number_of_instances = random.randint(min_required, 10)
282
+ if related_factory and related_instances:
283
+ number_to_create = random.randint(min_required, number_of_instances)
284
+ number_to_pick = number_of_instances - number_to_create
285
+ if number_to_pick > len(related_instances):
286
+ number_to_pick = len(related_instances)
287
+ existing_instances = random.sample(related_instances, number_to_pick)
288
+ new_instances = [related_factory() for _ in range(number_to_create)]
289
+ return existing_instances + new_instances
290
+ elif related_factory:
291
+ number_to_create = number_of_instances
292
+ new_instances = [related_factory() for _ in range(number_to_create)]
293
+ return new_instances
294
+ elif related_instances:
295
+ number_to_create = 0
296
+ number_to_pick = number_of_instances
297
+ if number_to_pick > len(related_instances):
298
+ number_to_pick = len(related_instances)
299
+ existing_instances = random.sample(related_instances, number_to_pick)
300
+ return existing_instances
278
301
  else:
279
- # No factory exists, use existing instances
280
- if existing_instances:
281
- max_instances = len(existing_instances)
282
- num_instances = random.randint(0, max_instances)
283
- return random.sample(existing_instances, num_instances)
284
- else:
285
- raise ValueError(
286
- f"No factory found for {field.related_model.__name__} and no instances found"
287
- )
302
+ raise ValueError(
303
+ f"No factory found for {field.related_model.__name__} and no instances found"
304
+ )
@@ -0,0 +1,109 @@
1
+ from typing import Any, Optional
2
+ from factory.declarations import LazyFunction, LazyAttribute, LazyAttributeSequence
3
+ import random
4
+ from general_manager.measurement.measurement import Measurement
5
+ from datetime import timedelta, date, datetime
6
+ from faker import Faker
7
+ import uuid
8
+ from decimal import Decimal
9
+
10
+ fake = Faker()
11
+
12
+
13
+ def LazyMeasurement(
14
+ min_value: int | float, max_value: int | float, unit: str
15
+ ) -> LazyFunction:
16
+ return LazyFunction(
17
+ lambda: Measurement(str(random.uniform(min_value, max_value))[:10], unit)
18
+ )
19
+
20
+
21
+ def LazyDeltaDate(avg_delta_days: int, base_attribute: str) -> LazyAttribute:
22
+ return LazyAttribute(
23
+ lambda obj: (getattr(obj, base_attribute) or date.today())
24
+ + timedelta(days=random.randint(avg_delta_days // 2, avg_delta_days * 3 // 2))
25
+ )
26
+
27
+
28
+ def LazyProjectName() -> LazyFunction:
29
+ return LazyFunction(
30
+ lambda: (
31
+ f"{fake.word().capitalize()} "
32
+ f"{fake.word().capitalize()} "
33
+ f"{fake.random_element(elements=('X', 'Z', 'G'))}"
34
+ f"-{fake.random_int(min=1, max=1000)}"
35
+ )
36
+ )
37
+
38
+
39
+ def LazyDateToday() -> LazyFunction:
40
+ return LazyFunction(lambda: date.today())
41
+
42
+
43
+ def LazyDateBetween(start_date: date, end_date: date) -> LazyAttribute:
44
+ delta = (end_date - start_date).days
45
+ return LazyAttribute(
46
+ lambda obj: start_date + timedelta(days=random.randint(0, delta))
47
+ )
48
+
49
+
50
+ def LazyDateTimeBetween(start: datetime, end: datetime) -> LazyAttribute:
51
+ span = (end - start).total_seconds()
52
+ return LazyAttribute(
53
+ lambda obj: start + timedelta(seconds=random.randint(0, int(span)))
54
+ )
55
+
56
+
57
+ def LazyInteger(min_value: int, max_value: int) -> LazyFunction:
58
+ return LazyFunction(lambda: random.randint(min_value, max_value))
59
+
60
+
61
+ def LazyDecimal(min_value: float, max_value: float, precision: int = 2) -> LazyFunction:
62
+ fmt = f"{{:.{precision}f}}"
63
+ return LazyFunction(
64
+ lambda: Decimal(fmt.format(random.uniform(min_value, max_value)))
65
+ )
66
+
67
+
68
+ def LazyChoice(options: list[Any]) -> LazyFunction:
69
+ return LazyFunction(lambda: random.choice(options))
70
+
71
+
72
+ def LazySequence(start: int = 0, step: int = 1) -> LazyAttributeSequence:
73
+ return LazyAttributeSequence(lambda obj, n: start + n * step)
74
+
75
+
76
+ def LazyBoolean(trues_ratio: float = 0.5) -> LazyFunction:
77
+ return LazyFunction(lambda: random.random() < trues_ratio)
78
+
79
+
80
+ def LazyUUID() -> LazyFunction:
81
+ return LazyFunction(lambda: str(uuid.uuid4()))
82
+
83
+
84
+ def LazyFakerName() -> LazyFunction:
85
+ return LazyFunction(lambda: fake.name())
86
+
87
+
88
+ def LazyFakerEmail(
89
+ name: Optional[str] = None, domain: Optional[str] = None
90
+ ) -> LazyFunction:
91
+ if not name and not domain:
92
+ return LazyFunction(lambda: fake.email(domain=domain))
93
+ if not name:
94
+ name = fake.name()
95
+ if not domain:
96
+ domain = fake.domain_name()
97
+ return LazyFunction(lambda: name.replace(" ", "_") + "@" + domain)
98
+
99
+
100
+ def LazyFakerSentence(number_of_words: int = 6) -> LazyFunction:
101
+ return LazyFunction(lambda: fake.sentence(nb_words=number_of_words))
102
+
103
+
104
+ def LazyFakerAddress() -> LazyFunction:
105
+ return LazyFunction(lambda: fake.address())
106
+
107
+
108
+ def LazyFakerUrl() -> LazyFunction:
109
+ return LazyFunction(lambda: fake.url())
@@ -46,6 +46,14 @@ class Measurement:
46
46
  def quantity(self) -> pint.Quantity:
47
47
  return self.__quantity
48
48
 
49
+ @property
50
+ def magnitude(self) -> Decimal:
51
+ return self.__quantity.magnitude
52
+
53
+ @property
54
+ def unit(self) -> str:
55
+ return str(self.__quantity.units)
56
+
49
57
  @classmethod
50
58
  def from_string(cls, value: str) -> Measurement:
51
59
  value, unit = value.split(" ")
@@ -0,0 +1,350 @@
1
+ # tests/test_factory_helpers.py
2
+ from datetime import date, datetime, timedelta
3
+ from decimal import Decimal
4
+
5
+ from django.db import models
6
+ from django.test import TestCase
7
+ from django.core.validators import RegexValidator
8
+
9
+ from factory.declarations import LazyFunction, LazyAttribute
10
+ from factory.faker import Faker
11
+ from general_manager.factory.factories import getFieldValue, getManyToManyFieldValue
12
+ from general_manager.measurement.measurementField import MeasurementField
13
+ from general_manager.measurement.measurement import Measurement
14
+ from unittest.mock import patch
15
+
16
+
17
+ class DummyForeignKey(models.Model):
18
+ """
19
+ Dummy ForeignKey model for testing purposes.
20
+ """
21
+
22
+ name = models.CharField(max_length=10, null=False)
23
+
24
+ class Meta:
25
+ app_label = "tests"
26
+ managed = False
27
+
28
+
29
+ class DummyForeignKey2(models.Model):
30
+ """
31
+ Dummy ForeignKey model for testing purposes.
32
+ """
33
+
34
+ name = models.CharField(max_length=10, null=False)
35
+
36
+ class Meta:
37
+ app_label = "tests"
38
+ managed = False
39
+
40
+
41
+ class DummyManyToMany(models.Model):
42
+ """
43
+ Dummy ManyToMany model for testing purposes.
44
+ """
45
+
46
+ name = models.CharField(max_length=10, null=False)
47
+
48
+ class Meta:
49
+ app_label = "tests"
50
+ managed = False
51
+
52
+
53
+ class DummyModel(models.Model):
54
+ # String without Regex‐Validator
55
+ char_field = models.CharField(max_length=10, null=False)
56
+ text_field = models.TextField(null=False)
57
+ # String with Regex‐Validator
58
+ regex_field = models.CharField(
59
+ max_length=10, null=False, validators=[RegexValidator(r"[A-Z]{3}\d{2}")]
60
+ )
61
+ # number types
62
+ int_field = models.IntegerField(null=False)
63
+ dec_field = models.DecimalField(max_digits=5, decimal_places=2, null=False)
64
+ float_field = models.FloatField(null=False)
65
+ # date/time types
66
+ date_field = models.DateField(null=False)
67
+ datetime_field = models.DateTimeField(null=False)
68
+ duration_field = models.DurationField(null=False)
69
+ # etc
70
+ bool_field = models.BooleanField(null=False)
71
+ email_field = models.EmailField(null=False)
72
+ url_field = models.URLField(null=False)
73
+ ip_field = models.GenericIPAddressField(null=False)
74
+ uuid_field = models.UUIDField(null=False)
75
+ # MeasurementField
76
+ measurement_field = MeasurementField(base_unit="kg", null=False)
77
+ # special fields
78
+ test_none = models.CharField(max_length=10, null=True)
79
+ dummy_fk = models.ForeignKey(
80
+ DummyForeignKey,
81
+ on_delete=models.CASCADE,
82
+ null=False,
83
+ )
84
+ dummy_one_to_one = models.OneToOneField(
85
+ DummyForeignKey2,
86
+ on_delete=models.CASCADE,
87
+ null=False,
88
+ )
89
+ dummy_m2m = models.ManyToManyField(
90
+ DummyManyToMany,
91
+ related_name="dummy_m2m",
92
+ blank=True,
93
+ )
94
+
95
+ class Meta:
96
+ app_label = "tests"
97
+ managed = False
98
+
99
+
100
+ class TestGetFieldValue(TestCase):
101
+ def _evaluate(self, declaration):
102
+ """
103
+ Evaluate a field declaration to get its value.
104
+ This is a helper method to handle different types of declarations.
105
+ """
106
+ obj = type("DummyModel", (object,), {})()
107
+ if isinstance(declaration, (LazyFunction, LazyAttribute, Faker)):
108
+ return declaration.evaluate(obj, None, {"locale": "en_US"})
109
+ return declaration
110
+
111
+ def test_all_not_relational_field_types(self):
112
+ field_expectations = [
113
+ # (fieldname, expected_type, optional: regex to match)
114
+ ("char_field", str, None),
115
+ ("text_field", str, None),
116
+ ("regex_field", str, r"^[A-Z]{3}\d{2}$"),
117
+ ("int_field", int, None),
118
+ ("dec_field", Decimal, None),
119
+ ("float_field", float, None),
120
+ ("date_field", date, None),
121
+ ("datetime_field", datetime, None),
122
+ ("duration_field", timedelta, None),
123
+ ("bool_field", bool, None),
124
+ ("email_field", str, r"^[^@]+@[^@]+\.[^@]+$"),
125
+ ("url_field", str, r"^https?://"),
126
+ ("ip_field", str, r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"),
127
+ ("uuid_field", str, r"^[0-9a-fA-F-]{36}$"),
128
+ ]
129
+
130
+ for name, expected_type, pattern in field_expectations:
131
+ with self.subTest(field=name):
132
+ field = DummyModel._meta.get_field(name)
133
+ decl = getFieldValue(field)
134
+
135
+ self.assertIn(
136
+ decl.__class__.__name__,
137
+ ("LazyFunction", "LazyAttribute", "NoneType", "Faker"),
138
+ msg=f"Unexpected declaration for {name}: {decl!r}",
139
+ )
140
+
141
+ value = self._evaluate(decl)
142
+
143
+ self.assertIsInstance(
144
+ value,
145
+ expected_type,
146
+ msg=f"Field {name!r} returned {value!r} ({type(value)})",
147
+ )
148
+
149
+ if pattern:
150
+ self.assertRegex(
151
+ str(value),
152
+ pattern,
153
+ msg=f"Value for {name!r} does not match {pattern}",
154
+ )
155
+
156
+ def test_nullable_field(self):
157
+ with patch(
158
+ "general_manager.factory.factories.random.choice",
159
+ return_value=True,
160
+ ):
161
+ field = DummyModel._meta.get_field("test_none")
162
+ decl = getFieldValue(field)
163
+ value = self._evaluate(decl)
164
+ self.assertIsNone(value, msg="Nullable field should return None")
165
+
166
+ def test_measurement_field(self):
167
+ field = DummyModel.measurement_field
168
+ decl = getFieldValue(field)
169
+ self.assertIsInstance(decl, LazyFunction)
170
+ value = decl.evaluate(None, None, None) # type: ignore
171
+ self.assertIsInstance(value, Measurement)
172
+ self.assertIsInstance(value.magnitude, Decimal)
173
+ self.assertIsInstance(value.unit, str)
174
+
175
+
176
+ class TestRelationFieldValue(TestCase):
177
+ def setUp(self):
178
+ # Aufräumen: kein _general_manager_class voraussetzen
179
+ for M in (DummyForeignKey, DummyForeignKey2):
180
+ if hasattr(M, "_general_manager_class"):
181
+ delattr(M, "_general_manager_class")
182
+
183
+ def test_fk_with_factory_new_instance(self):
184
+ # 1) _general_manager_class.Factory liefert direkt ein Objekt
185
+ dummy = DummyForeignKey(name="foo")
186
+
187
+ class GMC:
188
+ pass
189
+
190
+ GMC.Factory = lambda **kwargs: dummy # type: ignore
191
+ DummyForeignKey._general_manager_class = GMC # type: ignore
192
+ with patch(
193
+ "general_manager.factory.factoryMethods.random.choice", return_value=True
194
+ ):
195
+
196
+ field = DummyModel._meta.get_field("dummy_fk")
197
+ result = getFieldValue(field)
198
+ # Hier kommt kein LazyFunction, sondern direkt das factory-Ergebnis
199
+ self.assertIs(result, dummy)
200
+
201
+ def test_fk_with_factory_existing_instance(self):
202
+ dummy1 = DummyForeignKey(name="a")
203
+ dummy2 = DummyForeignKey(name="b")
204
+ field = DummyModel._meta.get_field("dummy_fk")
205
+
206
+ class GMC:
207
+ pass
208
+
209
+ GMC.Factory = lambda **kwargs: dummy1 # type: ignore
210
+ DummyForeignKey._general_manager_class = GMC # type: ignore
211
+
212
+ with (
213
+ patch(
214
+ "general_manager.factory.factories.random.choice",
215
+ return_value=False,
216
+ ),
217
+ patch.object(DummyForeignKey.objects, "all", return_value=[dummy1, dummy2]),
218
+ ):
219
+ decl = getFieldValue(field)
220
+ self.assertIsInstance(decl, LazyFunction)
221
+ inst = decl.evaluate(None, None, None) # type: ignore
222
+ self.assertIn(inst, (dummy1, dummy2))
223
+
224
+ def test_one_to_one_with_factory(self):
225
+ dummy = DummyForeignKey2(name="bar")
226
+
227
+ class GMC2:
228
+ pass
229
+
230
+ GMC2.Factory = lambda **kwargs: dummy # type: ignore
231
+ DummyForeignKey2._general_manager_class = GMC2 # type: ignore
232
+
233
+ field = DummyModel._meta.get_field("dummy_one_to_one")
234
+ result = getFieldValue(field)
235
+ self.assertIs(result, dummy)
236
+
237
+ def test_fk_without_factory_with_existing_instances(self):
238
+ # 2) kein factory, aber vorhandene Objekte → LazyFunction
239
+ dummy1 = DummyForeignKey(name="a")
240
+ dummy2 = DummyForeignKey(name="b")
241
+ field = DummyModel._meta.get_field("dummy_fk")
242
+
243
+ with patch.object(
244
+ DummyForeignKey.objects, "all", return_value=[dummy1, dummy2]
245
+ ):
246
+ decl = getFieldValue(field)
247
+ self.assertIsInstance(decl, LazyFunction)
248
+ # beim Evaluieren sollte eins der beiden Objekte zurückkommen
249
+ inst = decl.evaluate(None, None, None) # type: ignore
250
+ self.assertIn(inst, (dummy1, dummy2))
251
+
252
+ def test_one_to_one_without_factory_with_existing_instances(self):
253
+ dummy1 = DummyForeignKey2(name="x")
254
+ dummy2 = DummyForeignKey2(name="y")
255
+ field = DummyModel._meta.get_field("dummy_one_to_one")
256
+
257
+ with patch.object(
258
+ DummyForeignKey2.objects, "all", return_value=[dummy1, dummy2]
259
+ ):
260
+ decl = getFieldValue(field)
261
+ self.assertIsInstance(decl, LazyFunction)
262
+ inst = decl.evaluate(None, None, None) # type: ignore
263
+ self.assertIn(inst, (dummy1, dummy2))
264
+
265
+ def test_fk_without_factory_and_no_instances_raises(self):
266
+ field = DummyModel._meta.get_field("dummy_fk")
267
+ with (
268
+ patch.object(DummyForeignKey.objects, "all", return_value=[]),
269
+ self.assertRaisesMessage(
270
+ ValueError, "No factory found for DummyForeignKey"
271
+ ),
272
+ ):
273
+ getFieldValue(field)
274
+
275
+ def test_one_to_one_without_factory_and_no_instances_raises(self):
276
+ field = DummyModel._meta.get_field("dummy_one_to_one")
277
+ with (
278
+ patch.object(DummyForeignKey2.objects, "all", return_value=[]),
279
+ self.assertRaisesMessage(
280
+ ValueError, "No factory found for DummyForeignKey2"
281
+ ),
282
+ ):
283
+ getFieldValue(field)
284
+
285
+
286
+ class TestGetManyToManyFieldValue(TestCase):
287
+ def setUp(self):
288
+ # tidy up: no _general_manager_class assumed
289
+ for M in (DummyManyToMany, DummyModel):
290
+ if hasattr(M, "_general_manager_class"):
291
+ delattr(M, "_general_manager_class")
292
+
293
+ def test_m2m_with_factory_and_existing(self):
294
+ dummy1 = DummyManyToMany(name="foo", id=1)
295
+ dummy2 = DummyManyToMany(name="bar", id=2)
296
+
297
+ class GMC:
298
+ pass
299
+
300
+ GMC.Factory = lambda **kwargs: dummy1 # type: ignore
301
+ DummyManyToMany._general_manager_class = GMC # type: ignore
302
+
303
+ field = DummyModel._meta.get_field("dummy_m2m")
304
+ with patch.object(
305
+ field.related_model.objects, "all", return_value=[dummy1, dummy2] # type: ignore
306
+ ):
307
+ result = getManyToManyFieldValue(field) # type: ignore
308
+ self.assertIsInstance(result, list)
309
+ self.assertTrue(
310
+ set(result).issubset({dummy1, dummy2}),
311
+ "Returned instances are not a subset of existing objects",
312
+ )
313
+
314
+ def test_m2m_with_factory(self):
315
+ dummy1 = DummyManyToMany(name="foo", id=1)
316
+
317
+ class GMC:
318
+ pass
319
+
320
+ GMC.Factory = lambda **kwargs: dummy1 # type: ignore
321
+ DummyManyToMany._general_manager_class = GMC # type: ignore
322
+
323
+ field = DummyModel._meta.get_field("dummy_m2m")
324
+ with patch.object(field.related_model.objects, "all", return_value=[]): # type: ignore
325
+ result = getManyToManyFieldValue(field) # type: ignore
326
+ self.assertIsInstance(result, list)
327
+ self.assertIn(dummy1, result)
328
+
329
+ def test_m2m_without_factory(self):
330
+ dummy1 = DummyManyToMany(name="foo", id=1)
331
+ dummy2 = DummyManyToMany(name="bar", id=2)
332
+
333
+ field = DummyModel._meta.get_field("dummy_m2m")
334
+ with patch.object(
335
+ field.related_model.objects, "all", return_value=[dummy1, dummy2] # type: ignore
336
+ ):
337
+ result = getManyToManyFieldValue(field) # type: ignore
338
+ self.assertIsInstance(result, list)
339
+ self.assertTrue(
340
+ set(result).issubset({dummy1, dummy2}),
341
+ "Returned instances are not a subset of existing objects",
342
+ )
343
+
344
+ def test_m2m_without_factory_and_no_instances_raises(self):
345
+ field = DummyModel._meta.get_field("dummy_m2m")
346
+ with (
347
+ patch.object(field.related_model.objects, "all", return_value=[]), # type: ignore
348
+ self.assertRaises(ValueError),
349
+ ):
350
+ getManyToManyFieldValue(field) # type: ignore
@@ -0,0 +1,228 @@
1
+ from django.test import SimpleTestCase
2
+ from general_manager.factory.factoryMethods import (
3
+ LazyMeasurement,
4
+ LazyDeltaDate,
5
+ LazyProjectName,
6
+ LazyDateToday,
7
+ LazyDateBetween,
8
+ LazyDateTimeBetween,
9
+ LazyInteger,
10
+ LazyDecimal,
11
+ LazyUUID,
12
+ LazyBoolean,
13
+ LazyFakerName,
14
+ LazyFakerEmail,
15
+ LazyFakerSentence,
16
+ LazyFakerAddress,
17
+ LazyFakerUrl,
18
+ LazyChoice,
19
+ LazySequence,
20
+ )
21
+ from general_manager.measurement.measurement import Measurement
22
+ from datetime import date, datetime
23
+ from decimal import Decimal
24
+ from types import SimpleNamespace
25
+
26
+
27
+ class TestFactoryMethods(SimpleTestCase):
28
+ def test_LazyMeasurement(self):
29
+ min_value = 10.0
30
+ max_value = 30.5
31
+ unit = "kilogram"
32
+ obj = type("TestObject", (object,), {})()
33
+ for i in range(100):
34
+ with self.subTest(run=i):
35
+ measurement = LazyMeasurement(min_value, max_value, unit).evaluate(
36
+ obj, 1, None
37
+ )
38
+ self.assertIsInstance(measurement, Measurement)
39
+ self.assertTrue(min_value <= float(measurement.magnitude) <= max_value)
40
+ self.assertEqual(measurement.unit, unit)
41
+
42
+ def test_LazyDeltaDate(self):
43
+ avg_delta_days = 5 # -> 2.5 to 7.5 days
44
+ base_attribute = "start_date"
45
+ obj = type("TestObject", (object,), {base_attribute: date(2023, 1, 1)})()
46
+ for i in range(100):
47
+ with self.subTest(run=i):
48
+ delta_date = LazyDeltaDate(avg_delta_days, base_attribute).evaluate(
49
+ obj, 1, None
50
+ )
51
+ self.assertIsInstance(delta_date, date)
52
+ self.assertTrue(
53
+ date(2023, 1, 1) <= delta_date <= date(2023, 1, 8),
54
+ f"Run {i}: {delta_date} is not in the expected range.",
55
+ )
56
+
57
+ def test_LazyProjectName(self):
58
+ obj = type("TestObject", (object,), {})()
59
+ for i in range(100):
60
+ with self.subTest(run=i):
61
+ project_name = LazyProjectName().evaluate(obj, 1, None)
62
+ self.assertIsInstance(project_name, str)
63
+
64
+ def test_LazyDateToday(self):
65
+ obj = type("TestObject", (object,), {})()
66
+ for i in range(100):
67
+ with self.subTest(run=i):
68
+ date_today = LazyDateToday().evaluate(obj, 1, None)
69
+ self.assertIsInstance(date_today, date)
70
+ self.assertEqual(date_today, date.today())
71
+
72
+ def test_LazyDateBetween(self):
73
+ start_date = date(2023, 1, 1)
74
+ end_date = date(2023, 12, 31)
75
+ obj = type("TestObject", (object,), {})()
76
+ for i in range(100):
77
+ with self.subTest(run=i):
78
+ date_between = LazyDateBetween(start_date, end_date).evaluate(
79
+ obj, 1, None
80
+ )
81
+ self.assertIsInstance(date_between, date)
82
+ self.assertTrue(
83
+ start_date <= date_between <= end_date,
84
+ f"Run {i}: {date_between} is not in the expected range.",
85
+ )
86
+
87
+ def test_LazyDateTimeBetween(self):
88
+ start = datetime(2023, 1, 1)
89
+ end = datetime(2023, 12, 31)
90
+ obj = type("TestObject", (object,), {})()
91
+ for i in range(100):
92
+ with self.subTest(run=i):
93
+ datetime_between = LazyDateTimeBetween(start, end).evaluate(
94
+ obj, 1, None
95
+ )
96
+ self.assertIsInstance(datetime_between, datetime)
97
+ self.assertTrue(
98
+ start <= datetime_between <= end,
99
+ f"Run {i}: {datetime_between} is not in the expected range.",
100
+ )
101
+
102
+ def test_LazyInteger(self):
103
+ min_value = 1
104
+ max_value = 100
105
+ obj = type("TestObject", (object,), {})()
106
+ for i in range(100):
107
+ with self.subTest(run=i):
108
+ integer_value = LazyInteger(min_value, max_value).evaluate(obj, 1, None)
109
+ self.assertIsInstance(integer_value, int)
110
+ self.assertTrue(min_value <= integer_value <= max_value)
111
+
112
+ def test_LazyDecimal(self):
113
+ min_value = 1.0
114
+ max_value = 100.0
115
+ precision = 4
116
+ obj = type("TestObject", (object,), {})()
117
+ for i in range(100):
118
+ with self.subTest(run=i):
119
+ decimal_value = LazyDecimal(min_value, max_value, precision).evaluate(
120
+ obj, 1, None
121
+ )
122
+ self.assertIsInstance(decimal_value, Decimal)
123
+ self.assertTrue(
124
+ Decimal(min_value) <= decimal_value <= Decimal(max_value)
125
+ )
126
+ decimal_str = format(decimal_value, "f")
127
+ if "." in decimal_str:
128
+ self.assertEqual(len(decimal_str.split(".")[1]), precision)
129
+
130
+ def test_LazyUUID(self):
131
+ obj = type("TestObject", (object,), {})()
132
+ for i in range(100):
133
+ with self.subTest(run=i):
134
+ uuid_value = LazyUUID().evaluate(obj, 1, None)
135
+ self.assertIsInstance(uuid_value, str)
136
+ self.assertRegex(
137
+ uuid_value,
138
+ r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
139
+ )
140
+
141
+ def test_LazyBoolean(self):
142
+ obj = type("TestObject", (object,), {})()
143
+ for i in range(100):
144
+ with self.subTest(run=i):
145
+ boolean_value = LazyBoolean().evaluate(obj, 1, None)
146
+ self.assertIsInstance(boolean_value, bool)
147
+
148
+ def test_LazyFakerName(self):
149
+ obj = type("TestObject", (object,), {})()
150
+ for i in range(100):
151
+ with self.subTest(run=i):
152
+ name_value = LazyFakerName().evaluate(obj, 1, None)
153
+ self.assertIsInstance(name_value, str)
154
+ self.assertTrue(len(name_value) > 0)
155
+
156
+ def test_LazyFakerEmail(self):
157
+ obj = type("TestObject", (object,), {})()
158
+ for i in range(100):
159
+ with self.subTest(run=i):
160
+ email_value = LazyFakerEmail().evaluate(obj, 1, None)
161
+ self.assertIsInstance(email_value, str)
162
+ self.assertRegex(email_value, r"^[\w\.-]+@[\w\.-]+\.\w+$")
163
+
164
+ def test_LazyFakerEmail_with_presets(self):
165
+ obj = type("TestObject", (object,), {})()
166
+ names = [
167
+ "John Doe",
168
+ "Jane Smith",
169
+ "Alice Johnson",
170
+ "Bob Brown",
171
+ "Charlie Davis Jr.",
172
+ None,
173
+ None,
174
+ ]
175
+ domains = ["example.com", None]
176
+ for i, name in enumerate(names):
177
+ domain = domains[i % len(domains)]
178
+ with self.subTest(run=i):
179
+ email_value = LazyFakerEmail(name, domain).evaluate(obj, 1, None)
180
+ self.assertIsInstance(email_value, str)
181
+ self.assertRegex(email_value, r"^[\w\.-]+@[\w\.-]+\.\w+$")
182
+
183
+ def test_LazyFakerSentence(self):
184
+ obj = type("TestObject", (object,), {})()
185
+ for i in range(100):
186
+ with self.subTest(run=i):
187
+ sentence_value = LazyFakerSentence().evaluate(obj, 1, None)
188
+ self.assertIsInstance(sentence_value, str)
189
+ self.assertTrue(len(sentence_value) > 0)
190
+
191
+ def test_LazyFakerAddress(self):
192
+ obj = type("TestObject", (object,), {})()
193
+ for i in range(100):
194
+ with self.subTest(run=i):
195
+ address_value = LazyFakerAddress().evaluate(obj, 1, None)
196
+ self.assertIsInstance(address_value, str)
197
+ self.assertTrue(len(address_value) > 0)
198
+
199
+ def test_LazyFakerUrl(self):
200
+ obj = type("TestObject", (object,), {})()
201
+ for i in range(100):
202
+ with self.subTest(run=i):
203
+ url_value = LazyFakerUrl().evaluate(obj, 1, None)
204
+ self.assertIsInstance(url_value, str)
205
+ self.assertRegex(url_value, r"^https?://[^\s/$.?#].[^\s]*$")
206
+ self.assertTrue(len(url_value) > 0)
207
+
208
+ def test_LazyChoice(self):
209
+ options = ["option1", "option2", "option3"]
210
+ obj = type("TestObject", (object,), {})()
211
+ for i in range(100):
212
+ with self.subTest(run=i):
213
+ choice_value = LazyChoice(options).evaluate(obj, 1, None)
214
+ self.assertIn(choice_value, options)
215
+ self.assertIsInstance(choice_value, str)
216
+ self.assertTrue(len(choice_value) > 0)
217
+
218
+ def test_LazySequence(self):
219
+ start = 0
220
+ step = 2
221
+ obj = type("TestObject", (object,), {})()
222
+
223
+ for i in range(100):
224
+ with self.subTest(run=i):
225
+ context = SimpleNamespace(sequence=i)
226
+ sequence_value = LazySequence(start, step).evaluate(obj, context, None)
227
+ self.assertEqual(sequence_value, start + i * step)
228
+ self.assertIsInstance(sequence_value, int)
@@ -1,9 +1,9 @@
1
- from django.test import TestCase
1
+ from django.test import SimpleTestCase
2
2
  from general_manager.auxiliary.noneToZero import noneToZero
3
3
  from general_manager.measurement import Measurement
4
4
 
5
5
 
6
- class TestNoneToZero(TestCase):
6
+ class TestNoneToZero(SimpleTestCase):
7
7
 
8
8
  def test_none_to_zero(self):
9
9
  """
@@ -1,38 +0,0 @@
1
- from typing import Any
2
- from factory.declarations import LazyFunction, LazyAttribute, LazyAttributeSequence
3
- import random
4
- from general_manager.measurement.measurement import Measurement
5
- from datetime import timedelta, date
6
- from faker import Faker
7
-
8
- fake = Faker()
9
-
10
-
11
- def LazyMeasurement(
12
- min_value: int | float, max_value: int | float, unit: str
13
- ) -> LazyFunction:
14
- return LazyFunction(
15
- lambda: Measurement(str(random.uniform(min_value, max_value))[:10], unit)
16
- )
17
-
18
-
19
- def LazyDeltaDate(avg_delta_days: int, base_attribute: str) -> LazyAttribute:
20
- return LazyAttribute(
21
- lambda obj: (getattr(obj, base_attribute) or date.today())
22
- + timedelta(days=random.randint(avg_delta_days // 2, avg_delta_days * 3 // 2))
23
- )
24
-
25
-
26
- def LazyProjectName() -> LazyFunction:
27
- return LazyFunction(
28
- lambda: (
29
- f"{fake.word().capitalize()} "
30
- f"{fake.word().capitalize()} "
31
- f"{fake.random_element(elements=('X', 'Z', 'G'))}"
32
- f"-{fake.random_int(min=1, max=1000)}"
33
- )
34
- )
35
-
36
-
37
- def LazySapNumber() -> LazyAttributeSequence:
38
- return LazyAttributeSequence(lambda obj, n: f"60{n:04d}")
File without changes
File without changes
File without changes