Anonymous avatar Anonymous committed 0a2a37e

[1.2.X]Converted m2m_signals from doctests to unittests. Thanks to Gregor Müllegger for the patch. We have always been at war with doctests. Backport of [14548].

Comments (0)

Files changed (2)

tests/modeltests/m2m_signals/models.py

-"""
-Testing signals emitted on changing m2m relations.
-"""
+from django.db import models
 
-from django.db import models
 
 class Part(models.Model):
     name = models.CharField(max_length=20)
 
     def __unicode__(self):
         return self.name
-
-def m2m_changed_test(signal, sender, **kwargs):
-    print 'm2m_changed signal'
-    print 'instance:', kwargs['instance']
-    print 'action:', kwargs['action']
-    print 'reverse:', kwargs['reverse']
-    print 'model:', kwargs['model']
-    if kwargs['pk_set']:
-        print 'objects:',kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
-
-
-__test__ = {'API_TESTS':"""
-# Install a listener on one of the two m2m relations.
->>> models.signals.m2m_changed.connect(m2m_changed_test, Car.optional_parts.through)
-
-# Test the add, remove and clear methods on both sides of the
-# many-to-many relation
-
->>> c1 = Car.objects.create(name='VW')
->>> c2 = Car.objects.create(name='BMW')
->>> c3 = Car.objects.create(name='Toyota')
->>> p1 = Part.objects.create(name='Wheelset')
->>> p2 = Part.objects.create(name='Doors')
->>> p3 = Part.objects.create(name='Engine')
->>> p4 = Part.objects.create(name='Airbag')
->>> p5 = Part.objects.create(name='Sunroof')
-
-# adding a default part to our car - no signal listener installed
->>> c1.default_parts.add(p5)
-
-# Now install a listener
->>> models.signals.m2m_changed.connect(m2m_changed_test, Car.default_parts.through)
-
->>> c1.default_parts.add(p1, p2, p3)
-m2m_changed signal
-instance: VW
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>, <Part: Engine>, <Part: Wheelset>]
-m2m_changed signal
-instance: VW
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>, <Part: Engine>, <Part: Wheelset>]
-
-# give the BMW and Toyata some doors as well
->>> p2.car_set.add(c2, c3)
-m2m_changed signal
-instance: Doors
-action: pre_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: BMW>, <Car: Toyota>]
-m2m_changed signal
-instance: Doors
-action: post_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: BMW>, <Car: Toyota>]
-
-# remove the engine from the VW and the airbag (which is not set but is returned)
->>> c1.default_parts.remove(p3, p4)
-m2m_changed signal
-instance: VW
-action: pre_remove
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Airbag>, <Part: Engine>]
-m2m_changed signal
-instance: VW
-action: post_remove
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Airbag>, <Part: Engine>]
-
-# give the VW some optional parts (second relation to same model)
->>> c1.optional_parts.add(p4,p5)
-m2m_changed signal
-instance: VW
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Airbag>, <Part: Sunroof>]
-m2m_changed signal
-instance: VW
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Airbag>, <Part: Sunroof>]
-
-# add airbag to all the cars (even though the VW already has one)
->>> p4.cars_optional.add(c1, c2, c3)
-m2m_changed signal
-instance: Airbag
-action: pre_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: BMW>, <Car: Toyota>]
-m2m_changed signal
-instance: Airbag
-action: post_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: BMW>, <Car: Toyota>]
-
-# remove airbag from the VW (reverse relation with custom related_name)
->>> p4.cars_optional.remove(c1)
-m2m_changed signal
-instance: Airbag
-action: pre_remove
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: VW>]
-m2m_changed signal
-instance: Airbag
-action: post_remove
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: VW>]
-
-# clear all parts of the VW
->>> c1.default_parts.clear()
-m2m_changed signal
-instance: VW
-action: pre_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-m2m_changed signal
-instance: VW
-action: post_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-
-# take all the doors off of cars
->>> p2.car_set.clear()
-m2m_changed signal
-instance: Doors
-action: pre_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-m2m_changed signal
-instance: Doors
-action: post_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-
-# take all the airbags off of cars (clear reverse relation with custom related_name)
->>> p4.cars_optional.clear()
-m2m_changed signal
-instance: Airbag
-action: pre_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-m2m_changed signal
-instance: Airbag
-action: post_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-
-# alternative ways of setting relation:
-
->>> c1.default_parts.create(name='Windows')
-m2m_changed signal
-instance: VW
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Windows>]
-m2m_changed signal
-instance: VW
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Windows>]
-<Part: Windows>
-
-# direct assignment clears the set first, then adds
->>> c1.default_parts = [p1,p2,p3]
-m2m_changed signal
-instance: VW
-action: pre_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-m2m_changed signal
-instance: VW
-action: post_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-m2m_changed signal
-instance: VW
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>, <Part: Engine>, <Part: Wheelset>]
-m2m_changed signal
-instance: VW
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>, <Part: Engine>, <Part: Wheelset>]
-
-# Check that signals still work when model inheritance is involved
->>> c4 = SportsCar.objects.create(name='Bugatti', price='1000000')
->>> c4.default_parts = [p2]
-m2m_changed signal
-instance: Bugatti
-action: pre_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-m2m_changed signal
-instance: Bugatti
-action: post_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-m2m_changed signal
-instance: Bugatti
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>]
-m2m_changed signal
-instance: Bugatti
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Part'>
-objects: [<Part: Doors>]
-
->>> p3.car_set.add(c4)
-m2m_changed signal
-instance: Engine
-action: pre_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: Bugatti>]
-m2m_changed signal
-instance: Engine
-action: post_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Car'>
-objects: [<Car: Bugatti>]
-
-# Now test m2m relations with self
->>> p1 = Person.objects.create(name='Alice')
->>> p2 = Person.objects.create(name='Bob')
->>> p3 = Person.objects.create(name='Chuck')
->>> p4 = Person.objects.create(name='Daisy')
-
->>> models.signals.m2m_changed.connect(m2m_changed_test, Person.fans.through)
->>> models.signals.m2m_changed.connect(m2m_changed_test, Person.friends.through)
-
->>> p1.friends = [p2, p3]
-m2m_changed signal
-instance: Alice
-action: pre_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Alice
-action: post_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Alice
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Bob>, <Person: Chuck>]
-m2m_changed signal
-instance: Alice
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Bob>, <Person: Chuck>]
-
->>> p1.fans = [p4]
-m2m_changed signal
-instance: Alice
-action: pre_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Alice
-action: post_clear
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Alice
-action: pre_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Daisy>]
-m2m_changed signal
-instance: Alice
-action: post_add
-reverse: False
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Daisy>]
-
->>> p3.idols = [p1,p2]
-m2m_changed signal
-instance: Chuck
-action: pre_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Chuck
-action: post_clear
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Person'>
-m2m_changed signal
-instance: Chuck
-action: pre_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Alice>, <Person: Bob>]
-m2m_changed signal
-instance: Chuck
-action: post_add
-reverse: True
-model: <class 'modeltests.m2m_signals.models.Person'>
-objects: [<Person: Alice>, <Person: Bob>]
-
-# Cleanup - disconnect all signal handlers
->>> models.signals.m2m_changed.disconnect(m2m_changed_test, Car.default_parts.through)
->>> models.signals.m2m_changed.disconnect(m2m_changed_test, Car.optional_parts.through)
->>> models.signals.m2m_changed.disconnect(m2m_changed_test, Person.fans.through)
->>> models.signals.m2m_changed.disconnect(m2m_changed_test, Person.friends.through)
-
-"""}

tests/modeltests/m2m_signals/tests.py

+"""
+Testing signals emitted on changing m2m relations.
+"""
+
+from django.db import models
+from django.test import TestCase
+
+from models import Part, Car, SportsCar, Person
+
+
+class ManyToManySignalsTest(TestCase):
+    def m2m_changed_signal_receiver(self, signal, sender, **kwargs):
+        message = {
+            'instance': kwargs['instance'],
+            'action': kwargs['action'],
+            'reverse': kwargs['reverse'],
+            'model': kwargs['model'],
+        }
+        if kwargs['pk_set']:
+            message['objects'] = list(
+                kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
+            )
+        self.m2m_changed_messages.append(message)
+
+    def setUp(self):
+        self.m2m_changed_messages = []
+
+        self.vw = Car.objects.create(name='VW')
+        self.bmw = Car.objects.create(name='BMW')
+        self.toyota = Car.objects.create(name='Toyota')
+        self.wheelset = Part.objects.create(name='Wheelset')
+        self.doors = Part.objects.create(name='Doors')
+        self.engine = Part.objects.create(name='Engine')
+        self.airbag = Part.objects.create(name='Airbag')
+        self.sunroof = Part.objects.create(name='Sunroof')
+
+        self.alice = Person.objects.create(name='Alice')
+        self.bob = Person.objects.create(name='Bob')
+        self.chuck = Person.objects.create(name='Chuck')
+        self.daisy = Person.objects.create(name='Daisy')
+
+    def tearDown(self):
+        # disconnect all signal handlers
+        models.signals.m2m_changed.disconnect(
+            self.m2m_changed_signal_receiver, Car.default_parts.through
+        )
+        models.signals.m2m_changed.disconnect(
+            self.m2m_changed_signal_receiver, Car.optional_parts.through
+        )
+        models.signals.m2m_changed.disconnect(
+            self.m2m_changed_signal_receiver, Person.fans.through
+        )
+        models.signals.m2m_changed.disconnect(
+            self.m2m_changed_signal_receiver, Person.friends.through
+        )
+
+    def test_m2m_relations_add_remove_clear(self):
+        expected_messages = []
+
+        # Install a listener on one of the two m2m relations.
+        models.signals.m2m_changed.connect(
+            self.m2m_changed_signal_receiver, Car.optional_parts.through
+        )
+
+        # Test the add, remove and clear methods on both sides of the
+        # many-to-many relation
+
+        # adding a default part to our car - no signal listener installed
+        self.vw.default_parts.add(self.sunroof)
+
+        # Now install a listener
+        models.signals.m2m_changed.connect(
+            self.m2m_changed_signal_receiver, Car.default_parts.through
+        )
+
+        self.vw.default_parts.add(self.wheelset, self.doors, self.engine)
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors, self.engine, self.wheelset],
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors, self.engine, self.wheelset],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # give the BMW and Toyata some doors as well
+        self.doors.car_set.add(self.bmw, self.toyota)
+        expected_messages.append({
+            'instance': self.doors,
+            'action': 'pre_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.bmw, self.toyota],
+        })
+        expected_messages.append({
+            'instance': self.doors,
+            'action': 'post_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.bmw, self.toyota],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # remove the engine from the self.vw and the airbag (which is not set
+        # but is returned)
+        self.vw.default_parts.remove(self.engine, self.airbag)
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_remove',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.airbag, self.engine],
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_remove',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.airbag, self.engine],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # give the self.vw some optional parts (second relation to same model)
+        self.vw.optional_parts.add(self.airbag, self.sunroof)
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.airbag, self.sunroof],
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.airbag, self.sunroof],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # add airbag to all the cars (even though the self.vw already has one)
+        self.airbag.cars_optional.add(self.vw, self.bmw, self.toyota)
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'pre_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.bmw, self.toyota],
+        })
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'post_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.bmw, self.toyota],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # remove airbag from the self.vw (reverse relation with custom
+        # related_name)
+        self.airbag.cars_optional.remove(self.vw)
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'pre_remove',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.vw],
+        })
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'post_remove',
+            'reverse': True,
+            'model': Car,
+            'objects': [self.vw],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # clear all parts of the self.vw
+        self.vw.default_parts.clear()
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # take all the doors off of cars
+        self.doors.car_set.clear()
+        expected_messages.append({
+            'instance': self.doors,
+            'action': 'pre_clear',
+            'reverse': True,
+            'model': Car,
+        })
+        expected_messages.append({
+            'instance': self.doors,
+            'action': 'post_clear',
+            'reverse': True,
+            'model': Car,
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # take all the airbags off of cars (clear reverse relation with custom
+        # related_name)
+        self.airbag.cars_optional.clear()
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'pre_clear',
+            'reverse': True,
+            'model': Car,
+        })
+        expected_messages.append({
+            'instance': self.airbag,
+            'action': 'post_clear',
+            'reverse': True,
+            'model': Car,
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # alternative ways of setting relation:
+        self.vw.default_parts.create(name='Windows')
+        p6 = Part.objects.get(name='Windows')
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [p6],
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [p6],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # direct assignment clears the set first, then adds
+        self.vw.default_parts = [self.wheelset,self.doors,self.engine]
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors, self.engine, self.wheelset],
+        })
+        expected_messages.append({
+            'instance': self.vw,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors, self.engine, self.wheelset],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        # Check that signals still work when model inheritance is involved
+        c4 = SportsCar.objects.create(name='Bugatti', price='1000000')
+        c4b = Car.objects.get(name='Bugatti')
+        c4.default_parts = [self.doors]
+        expected_messages.append({
+            'instance': c4,
+            'action': 'pre_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        expected_messages.append({
+            'instance': c4,
+            'action': 'post_clear',
+            'reverse': False,
+            'model': Part,
+        })
+        expected_messages.append({
+            'instance': c4,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors],
+        })
+        expected_messages.append({
+            'instance': c4,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Part,
+            'objects': [self.doors],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        self.engine.car_set.add(c4)
+        expected_messages.append({
+            'instance': self.engine,
+            'action': 'pre_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [c4b],
+        })
+        expected_messages.append({
+            'instance': self.engine,
+            'action': 'post_add',
+            'reverse': True,
+            'model': Car,
+            'objects': [c4b],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+    def test_m2m_relations_with_self(self):
+        expected_messages = []
+
+        models.signals.m2m_changed.connect(
+            self.m2m_changed_signal_receiver, Person.fans.through
+        )
+        models.signals.m2m_changed.connect(
+            self.m2m_changed_signal_receiver, Person.friends.through
+        )
+
+        self.alice.friends = [self.bob, self.chuck]
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'pre_clear',
+            'reverse': False,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'post_clear',
+            'reverse': False,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Person,
+            'objects': [self.bob, self.chuck],
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Person,
+            'objects': [self.bob, self.chuck],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        self.alice.fans = [self.daisy]
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'pre_clear',
+            'reverse': False,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'post_clear',
+            'reverse': False,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'pre_add',
+            'reverse': False,
+            'model': Person,
+            'objects': [self.daisy],
+        })
+        expected_messages.append({
+            'instance': self.alice,
+            'action': 'post_add',
+            'reverse': False,
+            'model': Person,
+            'objects': [self.daisy],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
+
+        self.chuck.idols = [self.alice,self.bob]
+        expected_messages.append({
+            'instance': self.chuck,
+            'action': 'pre_clear',
+            'reverse': True,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.chuck,
+            'action': 'post_clear',
+            'reverse': True,
+            'model': Person,
+        })
+        expected_messages.append({
+            'instance': self.chuck,
+            'action': 'pre_add',
+            'reverse': True,
+            'model': Person,
+            'objects': [self.alice, self.bob],
+        })
+        expected_messages.append({
+            'instance': self.chuck,
+            'action': 'post_add',
+            'reverse': True,
+            'model': Person,
+            'objects': [self.alice, self.bob],
+        })
+        self.assertEqual(self.m2m_changed_messages, expected_messages)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.