Jeremy Stretch 2 дней назад
Родитель
Сommit
3ac7d8f117
1 измененных файлов с 175 добавлено и 0 удалено
  1. 175 0
      netbox/netbox/tests/test_ui.py

+ 175 - 0
netbox/netbox/tests/test_ui.py

@@ -1,3 +1,5 @@
+from types import SimpleNamespace
+
 from django.test import TestCase
 
 from circuits.choices import CircuitStatusChoices, VirtualCircuitTerminationRoleChoices
@@ -215,3 +217,176 @@ class RelatedObjectListAttrTest(TestCase):
         self.assertInHTML('<li>IKE Proposal 2</li>', rendered)
         self.assertNotIn('IKE Proposal 3', rendered)
         self.assertIn('…', rendered)
+
+
+class TextAttrTest(TestCase):
+
+    def test_get_value_with_format_string(self):
+        attr = attrs.TextAttr('asn', format_string='AS{}')
+        obj = SimpleNamespace(asn=65000)
+        self.assertEqual(attr.get_value(obj), 'AS65000')
+
+    def test_get_value_without_format_string(self):
+        attr = attrs.TextAttr('name')
+        obj = SimpleNamespace(name='foo')
+        self.assertEqual(attr.get_value(obj), 'foo')
+
+    def test_get_value_none_skips_format_string(self):
+        attr = attrs.TextAttr('name', format_string='prefix-{}')
+        obj = SimpleNamespace(name=None)
+        self.assertIsNone(attr.get_value(obj))
+
+    def test_get_context(self):
+        attr = attrs.TextAttr('name', style='text-monospace', copy_button=True)
+        obj = SimpleNamespace(name='bar')
+        context = attr.get_context(obj, 'name', 'bar', {})
+        self.assertEqual(context['style'], 'text-monospace')
+        self.assertTrue(context['copy_button'])
+
+
+class NumericAttrTest(TestCase):
+
+    def test_get_context_with_unit_accessor(self):
+        attr = attrs.NumericAttr('speed', unit_accessor='speed_unit')
+        obj = SimpleNamespace(speed=1000, speed_unit='Mbps')
+        context = attr.get_context(obj, 'speed', 1000, {})
+        self.assertEqual(context['unit'], 'Mbps')
+
+    def test_get_context_without_unit_accessor(self):
+        attr = attrs.NumericAttr('speed')
+        obj = SimpleNamespace(speed=1000)
+        context = attr.get_context(obj, 'speed', 1000, {})
+        self.assertIsNone(context['unit'])
+
+    def test_get_context_copy_button(self):
+        attr = attrs.NumericAttr('speed', copy_button=True)
+        obj = SimpleNamespace(speed=1000)
+        context = attr.get_context(obj, 'speed', 1000, {})
+        self.assertTrue(context['copy_button'])
+
+
+class BooleanAttrTest(TestCase):
+
+    def test_false_value_shown_by_default(self):
+        attr = attrs.BooleanAttr('enabled')
+        obj = SimpleNamespace(enabled=False)
+        self.assertIs(attr.get_value(obj), False)
+
+    def test_false_value_hidden_when_display_false_disabled(self):
+        attr = attrs.BooleanAttr('enabled', display_false=False)
+        obj = SimpleNamespace(enabled=False)
+        self.assertIsNone(attr.get_value(obj))
+
+    def test_true_value_always_shown(self):
+        attr = attrs.BooleanAttr('enabled', display_false=False)
+        obj = SimpleNamespace(enabled=True)
+        self.assertIs(attr.get_value(obj), True)
+
+
+class ImageAttrTest(TestCase):
+
+    def test_invalid_decoding_raises_value_error(self):
+        with self.assertRaises(ValueError):
+            attrs.ImageAttr('image', decoding='invalid')
+
+    def test_default_decoding_for_lazy_image(self):
+        attr = attrs.ImageAttr('image')
+        self.assertTrue(attr.load_lazy)
+        self.assertEqual(attr.decoding, 'async')
+
+    def test_default_decoding_for_non_lazy_image(self):
+        attr = attrs.ImageAttr('image', load_lazy=False)
+        self.assertFalse(attr.load_lazy)
+        self.assertIsNone(attr.decoding)
+
+    def test_explicit_decoding_value(self):
+        attr = attrs.ImageAttr('image', load_lazy=False, decoding='sync')
+        self.assertEqual(attr.decoding, 'sync')
+
+    def test_get_context(self):
+        attr = attrs.ImageAttr('image', load_lazy=False, decoding='async')
+        obj = SimpleNamespace(image='test.png')
+        context = attr.get_context(obj, 'image', 'test.png', {})
+        self.assertEqual(context['decoding'], 'async')
+        self.assertFalse(context['load_lazy'])
+
+
+class RelatedObjectAttrTest(TestCase):
+
+    def test_get_context_with_grouped_by(self):
+        region = SimpleNamespace(name='Region 1')
+        site = SimpleNamespace(name='Site 1', region=region)
+        obj = SimpleNamespace(site=site)
+        attr = attrs.RelatedObjectAttr('site', grouped_by='region')
+        context = attr.get_context(obj, 'site', site, {})
+        self.assertEqual(context['group'], region)
+
+    def test_get_context_without_grouped_by(self):
+        site = SimpleNamespace(name='Site 1')
+        obj = SimpleNamespace(site=site)
+        attr = attrs.RelatedObjectAttr('site')
+        context = attr.get_context(obj, 'site', site, {})
+        self.assertIsNone(context['group'])
+
+    def test_get_context_linkify(self):
+        site = SimpleNamespace(name='Site 1')
+        obj = SimpleNamespace(site=site)
+        attr = attrs.RelatedObjectAttr('site', linkify=True)
+        context = attr.get_context(obj, 'site', site, {})
+        self.assertTrue(context['linkify'])
+
+
+class GenericForeignKeyAttrTest(TestCase):
+
+    def test_get_context_content_type(self):
+        value = SimpleNamespace(_meta=SimpleNamespace(verbose_name='provider'))
+        obj = SimpleNamespace()
+        attr = attrs.GenericForeignKeyAttr('assigned_object')
+        context = attr.get_context(obj, 'assigned_object', value, {})
+        self.assertEqual(context['content_type'], 'provider')
+
+    def test_get_context_linkify(self):
+        value = SimpleNamespace(_meta=SimpleNamespace(verbose_name='provider'))
+        obj = SimpleNamespace()
+        attr = attrs.GenericForeignKeyAttr('assigned_object', linkify=True)
+        context = attr.get_context(obj, 'assigned_object', value, {})
+        self.assertTrue(context['linkify'])
+
+
+class GPSCoordinatesAttrTest(TestCase):
+
+    def test_missing_latitude_returns_placeholder(self):
+        attr = attrs.GPSCoordinatesAttr()
+        obj = SimpleNamespace(latitude=None, longitude=-74.006)
+        self.assertEqual(attr.render(obj, {'name': 'coordinates'}), attr.placeholder)
+
+    def test_missing_longitude_returns_placeholder(self):
+        attr = attrs.GPSCoordinatesAttr()
+        obj = SimpleNamespace(latitude=40.712, longitude=None)
+        self.assertEqual(attr.render(obj, {'name': 'coordinates'}), attr.placeholder)
+
+    def test_both_missing_returns_placeholder(self):
+        attr = attrs.GPSCoordinatesAttr()
+        obj = SimpleNamespace(latitude=None, longitude=None)
+        self.assertEqual(attr.render(obj, {'name': 'coordinates'}), attr.placeholder)
+
+
+class DateTimeAttrTest(TestCase):
+
+    def test_default_spec(self):
+        attr = attrs.DateTimeAttr('created')
+        obj = SimpleNamespace(created='2024-01-01')
+        context = attr.get_context(obj, 'created', '2024-01-01', {})
+        self.assertEqual(context['spec'], 'seconds')
+
+    def test_date_spec(self):
+        attr = attrs.DateTimeAttr('created', spec='date')
+        obj = SimpleNamespace(created='2024-01-01')
+        context = attr.get_context(obj, 'created', '2024-01-01', {})
+        self.assertEqual(context['spec'], 'date')
+
+    def test_minutes_spec(self):
+        attr = attrs.DateTimeAttr('created', spec='minutes')
+        obj = SimpleNamespace(created='2024-01-01')
+        context = attr.get_context(obj, 'created', '2024-01-01', {})
+        self.assertEqual(context['spec'], 'minutes')