diff -r cf47b83d8ad0 -r 752c5a5b73c6 tests/test-admin-commands.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-admin-commands.py Wed Jan 25 15:34:27 2023 +0100 @@ -0,0 +1,399 @@ +# Test admin commands + +import functools +import unittest +from mercurial.i18n import _ +from mercurial import error, ui as uimod +from mercurial import registrar +from mercurial.admin import verify + + +class TestAdminVerifyFindChecks(unittest.TestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ui = uimod.ui.load() + self.repo = b"fake-repo" + + def cleanup_table(self): + self.table = {} + self.alias_table = {} + self.pyramid = {} + + self.addCleanup(cleanup_table, self) + + def setUp(self): + self.table = {} + self.alias_table = {} + self.pyramid = {} + check = registrar.verify_check(self.table, self.alias_table) + + # mock some fake check method for tests purpose + @check( + b"test.dummy", + alias=b"dummy", + options=[], + ) + def check_dummy(ui, repo, **options): + return options + + @check( + b"test.fake", + alias=b"fake", + options=[ + (b'a', False, _(b'a boolean value (default: False)')), + (b'b', True, _(b'a boolean value (default: True)')), + (b'c', [], _(b'a list')), + ], + ) + def check_fake(ui, repo, **options): + return options + + # alias in the middle of a hierarchy + check( + b"test.noop", + alias=b"noop", + options=[], + )(verify.noop_func) + + @check( + b"test.noop.deeper", + alias=b"deeper", + options=[ + (b'y', True, _(b'a boolean value (default: True)')), + (b'z', [], _(b'a list')), + ], + ) + def check_noop_deeper(ui, repo, **options): + return options + + # args wrapper utilities + def find_checks(self, name): + return verify.find_checks( + name=name, + table=self.table, + alias_table=self.alias_table, + full_pyramid=self.pyramid, + ) + + def pass_options(self, checks, options): + return verify.pass_options( + self.ui, + checks, + options, + table=self.table, + alias_table=self.alias_table, + full_pyramid=self.pyramid, + ) + + def get_checks(self, names, options): + return verify.get_checks( + self.repo, + self.ui, + names=names, + options=options, + table=self.table, + alias_table=self.alias_table, + full_pyramid=self.pyramid, + ) + + # tests find_checks + def test_find_checks_empty_name(self): + with self.assertRaises(error.InputError): + self.find_checks(name=b"") + + def test_find_checks_wrong_name(self): + with self.assertRaises(error.InputError): + self.find_checks(name=b"unknown") + + def test_find_checks_dummy(self): + name = b"test.dummy" + found = self.find_checks(name=name) + self.assertEqual(len(found), 1) + self.assertIn(name, found) + meth = found[name] + self.assertTrue(callable(meth)) + self.assertEqual(len(meth.options), 0) + + def test_find_checks_fake(self): + name = b"test.fake" + found = self.find_checks(name=name) + self.assertEqual(len(found), 1) + self.assertIn(name, found) + meth = found[name] + self.assertTrue(callable(meth)) + self.assertEqual(len(meth.options), 3) + + def test_find_checks_noop(self): + name = b"test.noop.deeper" + found = self.find_checks(name=name) + self.assertEqual(len(found), 1) + self.assertIn(name, found) + meth = found[name] + self.assertTrue(callable(meth)) + self.assertEqual(len(meth.options), 2) + + def test_find_checks_from_aliases(self): + found = self.find_checks(name=b"dummy") + self.assertEqual(len(found), 1) + self.assertIn(b"test.dummy", found) + + found = self.find_checks(name=b"fake") + self.assertEqual(len(found), 1) + self.assertIn(b"test.fake", found) + + found = self.find_checks(name=b"deeper") + self.assertEqual(len(found), 1) + self.assertIn(b"test.noop.deeper", found) + + def test_find_checks_from_root(self): + found = self.find_checks(name=b"test") + self.assertEqual(len(found), 3) + self.assertIn(b"test.dummy", found) + self.assertIn(b"test.fake", found) + self.assertIn(b"test.noop.deeper", found) + + def test_find_checks_from_intermediate(self): + found = self.find_checks(name=b"test.noop") + self.assertEqual(len(found), 1) + self.assertIn(b"test.noop.deeper", found) + + def test_find_checks_from_parent_dot_name(self): + found = self.find_checks(name=b"noop.deeper") + self.assertEqual(len(found), 1) + self.assertIn(b"test.noop.deeper", found) + + # tests pass_options + def test_pass_options_no_checks_no_options(self): + checks = {} + options = [] + + with self.assertRaises(error.Error): + self.pass_options(checks=checks, options=options) + + def test_pass_options_fake_empty_options(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [] + # should end with default options + expected_options = {"a": False, "b": True, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + def test_pass_options_fake_non_existing_options(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + + with self.assertRaises(error.InputError): + options = [b"test.fake:boom=yes"] + self.pass_options(checks=funcs, options=options) + + def test_pass_options_fake_unrelated_options(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [b"test.noop.deeper:y=yes"] + + with self.assertRaises(error.InputError): + self.pass_options(checks=funcs, options=options) + + def test_pass_options_fake_set_option(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [b"test.fake:a=yes"] + expected_options = {"a": True, "b": True, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + def test_pass_options_fake_set_option_with_alias(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [b"fake:a=yes"] + expected_options = {"a": True, "b": True, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + def test_pass_options_fake_set_all_option(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [b"test.fake:a=yes", b"test.fake:b=no", b"test.fake:c=0,1,2"] + expected_options = {"a": True, "b": False, "c": [b"0", b"1", b"2"]} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + def test_pass_options_fake_set_all_option_plus_unexisting(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [ + b"test.fake:a=yes", + b"test.fake:b=no", + b"test.fake:c=0,1,2", + b"test.fake:d=0", + ] + + with self.assertRaises(error.InputError): + self.pass_options(checks=funcs, options=options) + + def test_pass_options_fake_duplicate_option(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [ + b"test.fake:a=yes", + b"test.fake:a=no", + ] + + with self.assertRaises(error.InputError): + self.pass_options(checks=funcs, options=options) + + def test_pass_options_fake_set_malformed_option(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + options = [ + b"test.fake:ayes", + b"test.fake:b==no", + b"test.fake=", + b"test.fake:", + b"test.fa=ke:d=0", + b"test.fa=ke:d=0", + ] + + for opt in options: + with self.assertRaises(error.InputError): + self.pass_options(checks=funcs, options=[opt]) + + def test_pass_options_types(self): + checks = self.find_checks(name=b"test.fake") + funcs = { + n: functools.partial(f, self.ui, self.repo) + for n, f in checks.items() + } + # boolean, yes/no + options = [b"test.fake:a=yes", b"test.fake:b=no"] + expected_options = {"a": True, "b": False, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + # boolean, 0/1 + options = [b"test.fake:a=1", b"test.fake:b=0"] + expected_options = {"a": True, "b": False, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + # boolean, true/false + options = [b"test.fake:a=true", b"test.fake:b=false"] + expected_options = {"a": True, "b": False, "c": []} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + # boolean, wrong type + options = [b"test.fake:a=si"] + with self.assertRaises(error.InputError): + self.pass_options(checks=funcs, options=options) + + # lists + options = [b"test.fake:c=0,1,2"] + expected_options = {"a": False, "b": True, "c": [b"0", b"1", b"2"]} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + options = [b"test.fake:c=x,y,z"] + expected_options = {"a": False, "b": True, "c": [b"x", b"y", b"z"]} + func = self.pass_options(checks=funcs, options=options) + + self.assertDictEqual(func[b"test.fake"].keywords, expected_options) + + # tests get_checks + def test_get_checks_fake(self): + funcs = self.get_checks( + names=[b"test.fake"], options=[b"test.fake:a=yes"] + ) + options = funcs.get(b"test.fake").keywords + expected_options = {"a": True, "b": True, "c": []} + self.assertDictEqual(options, expected_options) + + def test_get_checks_multiple_mixed_with_defaults(self): + funcs = self.get_checks( + names=[b"test.fake", b"test.noop.deeper", b"test.dummy"], + options=[ + b"test.noop.deeper:y=no", + b"test.noop.deeper:z=-1,0,1", + ], + ) + options = funcs.get(b"test.fake").keywords + expected_options = {"a": False, "b": True, "c": []} + self.assertDictEqual(options, expected_options) + + options = funcs.get(b"test.noop.deeper").keywords + expected_options = {"y": False, "z": [b"-1", b"0", b"1"]} + self.assertDictEqual(options, expected_options) + + options = funcs.get(b"test.dummy").keywords + expected_options = {} + self.assertDictEqual(options, expected_options) + + def test_broken_pyramid(self): + """Check that we detect pyramids that can't resolve""" + table = {} + alias_table = {} + pyramid = {} + check = registrar.verify_check(table, alias_table) + + # Create two checks that clash + @check(b"test.wrong.intermediate") + def check_dummy(ui, repo, **options): + return options + + @check(b"test.wrong.intermediate.thing") + def check_fake(ui, repo, **options): + return options + + with self.assertRaises(error.ProgrammingError) as e: + verify.get_checks( + self.repo, + self.ui, + names=[b"test.wrong.intermediate"], + options=[], + table=table, + alias_table=alias_table, + full_pyramid=pyramid, + ) + assert "`verify.noop_func`" in str(e.exception), str(e.exception) + + +if __name__ == '__main__': + import silenttestrunner + + silenttestrunner.main(__name__)