Skip to content

Commit ca021f7

Browse files
feature: add tests for util casing methods
1 parent c4c4f21 commit ca021f7

File tree

1 file changed

+78
-1
lines changed

1 file changed

+78
-1
lines changed

src/azure-cli-core/azure/cli/core/tests/test_util.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
(get_file_json, truncate_text, shell_safe_json_parse, b64_to_hex, hash_string, random_string,
1818
open_page_in_browser, can_launch_browser, handle_exception, ConfiguredDefaultSetter, send_raw_request,
1919
should_disable_connection_verify, parse_proxy_resource_id, get_az_user_agent, get_az_rest_user_agent,
20-
_get_parent_proc_name, is_wsl, run_cmd, run_az_cmd)
20+
_get_parent_proc_name, is_wsl, run_cmd, run_az_cmd, roughly_parse_command, roughly_parse_command_with_casing)
2121
from azure.cli.core.mock import DummyCli
2222

2323

@@ -612,6 +612,83 @@ def _get_mock_HttpOperationError(response_text):
612612

613613
return mock_http_error
614614

615+
def test_roughly_parse_command(self):
616+
"""Test roughly_parse_command function that extracts command parts and converts to lowercase"""
617+
# Basic command parsing
618+
self.assertEqual(roughly_parse_command(['az', 'vm', 'create']), 'az vm create')
619+
self.assertEqual(roughly_parse_command(['account', 'show']), 'account show')
620+
self.assertEqual(roughly_parse_command(['network', 'vnet', 'list']), 'network vnet list')
621+
622+
# Test case conversion - should convert to lowercase
623+
self.assertEqual(roughly_parse_command(['az', 'VM', 'CREATE']), 'az vm create')
624+
self.assertEqual(roughly_parse_command(['Account', 'Show']), 'account show')
625+
626+
# Test with flags - should stop at first flag and not include flag values
627+
self.assertEqual(roughly_parse_command(['az', 'vm', 'create', '--name', 'secretVM']), 'az vm create')
628+
self.assertEqual(roughly_parse_command(['az', 'storage', 'account', 'create', '--name', 'mystorageaccount']), 'az storage account create')
629+
self.assertEqual(roughly_parse_command(['az', 'keyvault', 'create', '--resource-group', 'myRG', '--name', 'myVault']), 'az keyvault create')
630+
631+
# Test with short flags
632+
self.assertEqual(roughly_parse_command(['az', 'vm', 'list', '-g', 'myResourceGroup']), 'az vm list')
633+
self.assertEqual(roughly_parse_command(['az', 'group', 'create', '-n', 'myGroup', '-l', 'eastus']), 'az group create')
634+
635+
# Edge cases
636+
self.assertEqual(roughly_parse_command([]), '')
637+
self.assertEqual(roughly_parse_command(['az']), 'az')
638+
self.assertEqual(roughly_parse_command(['--help']), '') # Starts with flag
639+
self.assertEqual(roughly_parse_command(['-h']), '') # Starts with short flag
640+
641+
def test_roughly_parse_command_with_casing(self):
642+
"""Test roughly_parse_command_with_casing function that preserves original casing"""
643+
# Basic command parsing with case preservation
644+
self.assertEqual(roughly_parse_command_with_casing(['az', 'vm', 'create']), 'az vm create')
645+
self.assertEqual(roughly_parse_command_with_casing(['account', 'show']), 'account show')
646+
self.assertEqual(roughly_parse_command_with_casing(['network', 'vnet', 'list']), 'network vnet list')
647+
648+
# Test case preservation - should keep original casing
649+
self.assertEqual(roughly_parse_command_with_casing(['az', 'VM', 'CREATE']), 'az VM CREATE')
650+
self.assertEqual(roughly_parse_command_with_casing(['Account', 'Show']), 'Account Show')
651+
self.assertEqual(roughly_parse_command_with_casing(['Az', 'Network', 'Vnet', 'List']), 'Az Network Vnet List')
652+
653+
# Test with flags - should stop at first flag and not include sensitive flag values
654+
self.assertEqual(roughly_parse_command_with_casing(['az', 'vm', 'create', '--name', 'secretVM']), 'az vm create')
655+
self.assertEqual(roughly_parse_command_with_casing(['az', 'VM', 'Create', '--name', 'superSecretVM']), 'az VM Create')
656+
self.assertEqual(roughly_parse_command_with_casing(['az', 'storage', 'account', 'create', '--name', 'mystorageaccount']), 'az storage account create')
657+
self.assertEqual(roughly_parse_command_with_casing(['az', 'keyvault', 'create', '--resource-group', 'myRG', '--name', 'myVault']), 'az keyvault create')
658+
659+
# Test with short flags
660+
self.assertEqual(roughly_parse_command_with_casing(['az', 'VM', 'list', '-g', 'myResourceGroup']), 'az VM list')
661+
self.assertEqual(roughly_parse_command_with_casing(['az', 'Group', 'create', '-n', 'myGroup', '-l', 'eastus']), 'az Group create')
662+
663+
# Test mixed case scenarios that might reveal user typing patterns
664+
self.assertEqual(roughly_parse_command_with_casing(['Az', 'Vm', 'Create']), 'Az Vm Create')
665+
self.assertEqual(roughly_parse_command_with_casing(['AZ', 'STORAGE', 'BLOB', 'LIST']), 'AZ STORAGE BLOB LIST')
666+
667+
# Edge cases
668+
self.assertEqual(roughly_parse_command_with_casing([]), '')
669+
self.assertEqual(roughly_parse_command_with_casing(['az']), 'az')
670+
self.assertEqual(roughly_parse_command_with_casing(['Az']), 'Az')
671+
self.assertEqual(roughly_parse_command_with_casing(['--help']), '') # Starts with flag
672+
self.assertEqual(roughly_parse_command_with_casing(['-h']), '') # Starts with short flag
673+
674+
# Security test - ensure no sensitive information leaks after flags
675+
test_cases_with_secrets = [
676+
(['az', 'vm', 'create', '--admin-password', 'SuperSecret123!'], 'az vm create'),
677+
(['az', 'sql', 'server', 'create', '--admin-user', 'admin', '--admin-password', 'VerySecret!'], 'az sql server create'),
678+
(['az', 'storage', 'account', 'create', '--name', 'storageacct', '--access-tier', 'Hot'], 'az storage account create'),
679+
(['Az', 'KeyVault', 'Secret', 'Set', '--vault-name', 'myVault', '--name', 'secretName', '--value', 'topSecret'], 'Az KeyVault Secret Set')
680+
]
681+
682+
for args, expected in test_cases_with_secrets:
683+
with self.subTest(args=args):
684+
result = roughly_parse_command_with_casing(args)
685+
self.assertEqual(result, expected)
686+
# Ensure no sensitive values made it through
687+
self.assertNotIn('SuperSecret123!', result)
688+
self.assertNotIn('VerySecret!', result)
689+
self.assertNotIn('topSecret', result)
690+
self.assertNotIn('storageacct', result) # Even non-secret values after flags should not appear
691+
615692

616693
if __name__ == '__main__':
617694
unittest.main()

0 commit comments

Comments
 (0)