summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2021-12-31 10:30:48 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-01-03 12:30:51 +0100
commit0ab58c120939093fea90822f376e1866fc714d1f (patch)
tree83c0412efaf60c2715d5c3ffe8cd9e67dccb1fea /tests
parent03a648811615cb623affc2d79dccd4b05919319e (diff)
Refs #29026 -- Allowed customizing InteractiveMigrationQuestioner's prompt destination.
Previously, the questioner did not obey the value of stdout provided to the command.
Diffstat (limited to 'tests')
-rw-r--r--tests/migrations/test_commands.py49
-rw-r--r--tests/migrations/test_questioner.py39
2 files changed, 46 insertions, 42 deletions
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index bf78b60a85..ef5db241d6 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -1304,7 +1304,15 @@ class MakeMigrationsTests(MigrationTestBase):
# Monkeypatch interactive questioner to auto reject
with mock.patch('builtins.input', mock.Mock(return_value='N')):
with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir:
- call_command("makemigrations", "migrations", name="merge", merge=True, interactive=True, verbosity=0)
+ with captured_stdout():
+ call_command(
+ 'makemigrations',
+ 'migrations',
+ name='merge',
+ merge=True,
+ interactive=True,
+ verbosity=0,
+ )
merge_file = os.path.join(migration_dir, '0003_merge.py')
self.assertFalse(os.path.exists(merge_file))
@@ -1766,6 +1774,10 @@ class MakeMigrationsTests(MigrationTestBase):
' - remove field silly_field from author\n'
' - add field rating to author\n'
' - create model book\n'
+ '\n'
+ 'merging will only work if the operations printed above do not conflict\n'
+ 'with each other (working on different fields or models)\n'
+ 'should these migration branches be merged? [y/n] '
)
def test_makemigrations_with_custom_name(self):
@@ -1886,30 +1898,25 @@ class MakeMigrationsTests(MigrationTestBase):
"It is impossible to add the field 'creation_date' with "
"'auto_now_add=True' to entry without providing a default. This "
"is because the database needs something to populate existing "
- "rows.\n\n"
+ "rows.\n"
" 1) Provide a one-off default now which will be set on all "
"existing rows\n"
" 2) Quit and manually define a default value in models.py."
)
# Monkeypatch interactive questioner to auto accept
- with mock.patch('django.db.migrations.questioner.sys.stdout', new_callable=io.StringIO) as prompt_stdout:
- out = io.StringIO()
- with self.temporary_migration_module(module='migrations.test_auto_now_add'):
- call_command('makemigrations', 'migrations', interactive=True, stdout=out)
- output = out.getvalue()
- prompt_output = prompt_stdout.getvalue()
- self.assertIn(input_msg, prompt_output)
- self.assertIn(
- 'Please enter the default value as valid Python.',
- prompt_output,
- )
- self.assertIn(
- "Accept the default 'timezone.now' by pressing 'Enter' or "
- "provide another value.",
- prompt_output,
- )
- self.assertIn("Type 'exit' to exit this prompt", prompt_output)
- self.assertIn("Add field creation_date to entry", output)
+ prompt_stdout = io.StringIO()
+ with self.temporary_migration_module(module='migrations.test_auto_now_add'):
+ call_command('makemigrations', 'migrations', interactive=True, stdout=prompt_stdout)
+ prompt_output = prompt_stdout.getvalue()
+ self.assertIn(input_msg, prompt_output)
+ self.assertIn('Please enter the default value as valid Python.', prompt_output)
+ self.assertIn(
+ "Accept the default 'timezone.now' by pressing 'Enter' or provide "
+ "another value.",
+ prompt_output,
+ )
+ self.assertIn("Type 'exit' to exit this prompt", prompt_output)
+ self.assertIn("Add field creation_date to entry", prompt_output)
@mock.patch('builtins.input', return_value='2')
def test_makemigrations_auto_now_add_interactive_quit(self, mock_input):
@@ -1960,7 +1967,7 @@ class MakeMigrationsTests(MigrationTestBase):
input_msg = (
f'Callable default on unique field book.created will not generate '
f'unique values upon migrating.\n'
- f'Please choose how to proceed:\n\n'
+ f'Please choose how to proceed:\n'
f' 1) Continue making this migration as the first step in writing '
f'a manual migration to generate unique values described here: '
f'https://docs.djangoproject.com/en/{version}/howto/'
diff --git a/tests/migrations/test_questioner.py b/tests/migrations/test_questioner.py
index c9690d0b99..472a3f248f 100644
--- a/tests/migrations/test_questioner.py
+++ b/tests/migrations/test_questioner.py
@@ -1,12 +1,14 @@
import datetime
+from io import StringIO
from unittest import mock
+from django.core.management.base import OutputWrapper
from django.db.migrations.questioner import (
InteractiveMigrationQuestioner, MigrationQuestioner,
)
from django.db.models import NOT_PROVIDED
from django.test import SimpleTestCase
-from django.test.utils import captured_stdout, override_settings
+from django.test.utils import override_settings
class QuestionerTests(SimpleTestCase):
@@ -24,65 +26,60 @@ class QuestionerTests(SimpleTestCase):
@mock.patch('builtins.input', return_value='2')
def test_ask_not_null_alteration_not_provided(self, mock):
- questioner = InteractiveMigrationQuestioner()
- with captured_stdout():
- question = questioner.ask_not_null_alteration('field_name', 'model_name')
+ questioner = InteractiveMigrationQuestioner(prompt_output=OutputWrapper(StringIO()))
+ question = questioner.ask_not_null_alteration('field_name', 'model_name')
self.assertEqual(question, NOT_PROVIDED)
class QuestionerHelperMethodsTests(SimpleTestCase):
- questioner = InteractiveMigrationQuestioner()
+ def setUp(self):
+ self.prompt = OutputWrapper(StringIO())
+ self.questioner = InteractiveMigrationQuestioner(prompt_output=self.prompt)
@mock.patch('builtins.input', return_value='datetime.timedelta(days=1)')
def test_questioner_default_timedelta(self, mock_input):
- questioner = InteractiveMigrationQuestioner()
- with captured_stdout():
- value = questioner._ask_default()
+ value = self.questioner._ask_default()
self.assertEqual(value, datetime.timedelta(days=1))
@mock.patch('builtins.input', return_value='')
def test_questioner_default_no_user_entry(self, mock_input):
- with captured_stdout():
- value = self.questioner._ask_default(default='datetime.timedelta(days=1)')
+ value = self.questioner._ask_default(default='datetime.timedelta(days=1)')
self.assertEqual(value, datetime.timedelta(days=1))
@mock.patch('builtins.input', side_effect=['', 'exit'])
def test_questioner_no_default_no_user_entry(self, mock_input):
- with captured_stdout() as stdout, self.assertRaises(SystemExit):
+ with self.assertRaises(SystemExit):
self.questioner._ask_default()
self.assertIn(
"Please enter some code, or 'exit' (without quotes) to exit.",
- stdout.getvalue(),
+ self.prompt.getvalue(),
)
@mock.patch('builtins.input', side_effect=['bad code', 'exit'])
def test_questioner_no_default_bad_user_entry_code(self, mock_input):
- with captured_stdout() as stdout, self.assertRaises(SystemExit):
+ with self.assertRaises(SystemExit):
self.questioner._ask_default()
- self.assertIn('Invalid input: ', stdout.getvalue())
+ self.assertIn('Invalid input: ', self.prompt.getvalue())
@mock.patch('builtins.input', side_effect=['', 'n'])
def test_questioner_no_default_no_user_entry_boolean(self, mock_input):
- with captured_stdout():
- value = self.questioner._boolean_input('Proceed?')
+ value = self.questioner._boolean_input('Proceed?')
self.assertIs(value, False)
@mock.patch('builtins.input', return_value='')
def test_questioner_default_no_user_entry_boolean(self, mock_input):
- with captured_stdout():
- value = self.questioner._boolean_input('Proceed?', default=True)
+ value = self.questioner._boolean_input('Proceed?', default=True)
self.assertIs(value, True)
@mock.patch('builtins.input', side_effect=[10, 'garbage', 1])
def test_questioner_bad_user_choice(self, mock_input):
question = 'Make a choice:'
- with captured_stdout() as stdout:
- value = self.questioner._choice_input(question, choices='abc')
+ value = self.questioner._choice_input(question, choices='abc')
expected_msg = (
f'{question}\n'
f' 1) a\n'
f' 2) b\n'
f' 3) c\n'
)
- self.assertIn(expected_msg, stdout.getvalue())
+ self.assertIn(expected_msg, self.prompt.getvalue())
self.assertEqual(value, 1)