mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[test] Show all differences for expect_value and expect_dict (#12334)
				
					
				
			Authored by: Grub4K
This commit is contained in:
		
							
								
								
									
										172
									
								
								test/helper.py
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								test/helper.py
									
									
									
									
									
								
							| @@ -101,87 +101,109 @@ def getwebpagetestcases(): | ||||
| md5 = lambda s: hashlib.md5(s.encode()).hexdigest() | ||||
| 
 | ||||
| 
 | ||||
| def expect_value(self, got, expected, field): | ||||
|     if isinstance(expected, str) and expected.startswith('re:'): | ||||
|         match_str = expected[len('re:'):] | ||||
|         match_rex = re.compile(match_str) | ||||
| def _iter_differences(got, expected, field): | ||||
|     if isinstance(expected, str): | ||||
|         op, _, val = expected.partition(':') | ||||
|         if op in ('mincount', 'maxcount', 'count'): | ||||
|             if not isinstance(got, (list, dict)): | ||||
|                 yield field, f'expected either {list.__name__} or {dict.__name__}, got {type(got).__name__}' | ||||
|                 return | ||||
| 
 | ||||
|         self.assertTrue( | ||||
|             isinstance(got, str), | ||||
|             f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}') | ||||
|         self.assertTrue( | ||||
|             match_rex.match(got), | ||||
|             f'field {field} (value: {got!r}) should match {match_str!r}') | ||||
|     elif isinstance(expected, str) and expected.startswith('startswith:'): | ||||
|         start_str = expected[len('startswith:'):] | ||||
|         self.assertTrue( | ||||
|             isinstance(got, str), | ||||
|             f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}') | ||||
|         self.assertTrue( | ||||
|             got.startswith(start_str), | ||||
|             f'field {field} (value: {got!r}) should start with {start_str!r}') | ||||
|     elif isinstance(expected, str) and expected.startswith('contains:'): | ||||
|         contains_str = expected[len('contains:'):] | ||||
|         self.assertTrue( | ||||
|             isinstance(got, str), | ||||
|             f'Expected a {str.__name__} object, but got {type(got).__name__} for field {field}') | ||||
|         self.assertTrue( | ||||
|             contains_str in got, | ||||
|             f'field {field} (value: {got!r}) should contain {contains_str!r}') | ||||
|     elif isinstance(expected, type): | ||||
|         self.assertTrue( | ||||
|             isinstance(got, expected), | ||||
|             f'Expected type {expected!r} for field {field}, but got value {got!r} of type {type(got)!r}') | ||||
|     elif isinstance(expected, dict) and isinstance(got, dict): | ||||
|         expect_dict(self, got, expected) | ||||
|     elif isinstance(expected, list) and isinstance(got, list): | ||||
|         self.assertEqual( | ||||
|             len(expected), len(got), | ||||
|             f'Expect a list of length {len(expected)}, but got a list of length {len(got)} for field {field}') | ||||
|         for index, (item_got, item_expected) in enumerate(zip(got, expected)): | ||||
|             type_got = type(item_got) | ||||
|             type_expected = type(item_expected) | ||||
|             self.assertEqual( | ||||
|                 type_expected, type_got, | ||||
|                 f'Type mismatch for list item at index {index} for field {field}, ' | ||||
|                 f'expected {type_expected!r}, got {type_got!r}') | ||||
|             expect_value(self, item_got, item_expected, field) | ||||
|     else: | ||||
|         if isinstance(expected, str) and expected.startswith('md5:'): | ||||
|             self.assertTrue( | ||||
|                 isinstance(got, str), | ||||
|                 f'Expected field {field} to be a unicode object, but got value {got!r} of type {type(got)!r}') | ||||
|             got = 'md5:' + md5(got) | ||||
|         elif isinstance(expected, str) and re.match(r'^(?:min|max)?count:\d+', expected): | ||||
|             self.assertTrue( | ||||
|                 isinstance(got, (list, dict)), | ||||
|                 f'Expected field {field} to be a list or a dict, but it is of type {type(got).__name__}') | ||||
|             op, _, expected_num = expected.partition(':') | ||||
|             expected_num = int(expected_num) | ||||
|             expected_num = int(val) | ||||
|             got_num = len(got) | ||||
|             if op == 'mincount': | ||||
|                 assert_func = assertGreaterEqual | ||||
|                 msg_tmpl = 'Expected %d items in field %s, but only got %d' | ||||
|             elif op == 'maxcount': | ||||
|                 assert_func = assertLessEqual | ||||
|                 msg_tmpl = 'Expected maximum %d items in field %s, but got %d' | ||||
|             elif op == 'count': | ||||
|                 assert_func = assertEqual | ||||
|                 msg_tmpl = 'Expected exactly %d items in field %s, but got %d' | ||||
|             else: | ||||
|                 assert False | ||||
|             assert_func( | ||||
|                 self, len(got), expected_num, | ||||
|                 msg_tmpl % (expected_num, field, len(got))) | ||||
|                 if got_num < expected_num: | ||||
|                     yield field, f'expected at least {val} items, got {got_num}' | ||||
|                 return | ||||
| 
 | ||||
|             if op == 'maxcount': | ||||
|                 if got_num > expected_num: | ||||
|                     yield field, f'expected at most {val} items, got {got_num}' | ||||
|                 return | ||||
| 
 | ||||
|             assert op == 'count' | ||||
|             if got_num != expected_num: | ||||
|                 yield field, f'expected exactly {val} items, got {got_num}' | ||||
|             return | ||||
|         self.assertEqual( | ||||
|             expected, got, | ||||
|             f'Invalid value for field {field}, expected {expected!r}, got {got!r}') | ||||
| 
 | ||||
|         if not isinstance(got, str): | ||||
|             yield field, f'expected {str.__name__}, got {type(got).__name__}' | ||||
|             return | ||||
| 
 | ||||
|         if op == 're': | ||||
|             if not re.match(val, got): | ||||
|                 yield field, f'should match {val!r}, got {got!r}' | ||||
|             return | ||||
| 
 | ||||
|         if op == 'startswith': | ||||
|             if not val.startswith(got): | ||||
|                 yield field, f'should start with {val!r}, got {got!r}' | ||||
|             return | ||||
| 
 | ||||
|         if op == 'contains': | ||||
|             if not val.startswith(got): | ||||
|                 yield field, f'should contain {val!r}, got {got!r}' | ||||
|             return | ||||
| 
 | ||||
|         if op == 'md5': | ||||
|             hash_val = md5(got) | ||||
|             if hash_val != val: | ||||
|                 yield field, f'expected hash {val}, got {hash_val}' | ||||
|             return | ||||
| 
 | ||||
|         if got != expected: | ||||
|             yield field, f'expected {expected!r}, got {got!r}' | ||||
|         return | ||||
| 
 | ||||
|     if isinstance(expected, dict) and isinstance(got, dict): | ||||
|         for key, expected_val in expected.items(): | ||||
|             if key not in got: | ||||
|                 yield field, f'missing key: {key!r}' | ||||
|                 continue | ||||
| 
 | ||||
|             field_name = key if field is None else f'{field}.{key}' | ||||
|             yield from _iter_differences(got[key], expected_val, field_name) | ||||
|         return | ||||
| 
 | ||||
|     if isinstance(expected, type): | ||||
|         if not isinstance(got, expected): | ||||
|             yield field, f'expected {expected.__name__}, got {type(got).__name__}' | ||||
|         return | ||||
| 
 | ||||
|     if isinstance(expected, list) and isinstance(got, list): | ||||
|         # TODO: clever diffing algorithm lmao | ||||
|         if len(expected) != len(got): | ||||
|             yield field, f'expected length of {len(expected)}, got {len(got)}' | ||||
|             return | ||||
| 
 | ||||
|         for index, (got_val, expected_val) in enumerate(zip(got, expected)): | ||||
|             field_name = str(index) if field is None else f'{field}.{index}' | ||||
|             yield from _iter_differences(got_val, expected_val, field_name) | ||||
|         return | ||||
| 
 | ||||
|     if got != expected: | ||||
|         yield field, f'expected {expected!r}, got {got!r}' | ||||
| 
 | ||||
| 
 | ||||
| def _expect_value(message, got, expected, field): | ||||
|     mismatches = list(_iter_differences(got, expected, field)) | ||||
|     if not mismatches: | ||||
|         return | ||||
| 
 | ||||
|     fields = [field for field, _ in mismatches if field is not None] | ||||
|     return ''.join(( | ||||
|         message, f' ({", ".join(fields)})' if fields else '', | ||||
|         *(f'\n\t{field}: {message}' for field, message in mismatches))) | ||||
| 
 | ||||
| 
 | ||||
| def expect_value(self, got, expected, field): | ||||
|     if message := _expect_value('values differ', got, expected, field): | ||||
|         self.fail(message) | ||||
| 
 | ||||
| 
 | ||||
| def expect_dict(self, got_dict, expected_dict): | ||||
|     for info_field, expected in expected_dict.items(): | ||||
|         got = got_dict.get(info_field) | ||||
|         expect_value(self, got, expected, info_field) | ||||
|     if message := _expect_value('dictionaries differ', got_dict, expected_dict, None): | ||||
|         self.fail(message) | ||||
| 
 | ||||
| 
 | ||||
| def sanitize_got_info_dict(got_dict): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Simon Sawicki
					Simon Sawicki