mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
194 lines
6.5 KiB
Python
194 lines
6.5 KiB
Python
import unittest
|
|
from typing import Iterator, List, Union, Dict
|
|
from propsutil import get_entry_dict
|
|
from enum import Enum
|
|
|
|
|
|
class ChangeType(Enum):
|
|
"""Describes the nature of a change in the properties file."""
|
|
ADDITION = 'ADDITION'
|
|
DELETION = 'DELETION'
|
|
CHANGE = 'CHANGE'
|
|
|
|
|
|
class ItemChange:
|
|
rel_path: str
|
|
key: str
|
|
prev_val: Union[str, None]
|
|
cur_val: Union[str, None]
|
|
type: ChangeType
|
|
|
|
def __init__(self, rel_path: str, key: str, prev_val: str, cur_val: str):
|
|
"""Describes the change that occurred for a particular key of a properties file.
|
|
|
|
Args:
|
|
rel_path (str): The relative path of the properties file.
|
|
key (str): The key in the properties file.
|
|
prev_val (str): The previous value for the key.
|
|
cur_val (str): The current value for the key.
|
|
"""
|
|
self.rel_path = rel_path
|
|
self.key = key
|
|
self.prev_val = prev_val
|
|
self.cur_val = cur_val
|
|
if ItemChange.has_str_content(cur_val) and not ItemChange.has_str_content(prev_val):
|
|
self.type = ChangeType.ADDITION
|
|
elif not ItemChange.has_str_content(cur_val) and ItemChange.has_str_content(prev_val):
|
|
self.type = ChangeType.DELETION
|
|
else:
|
|
self.type = ChangeType.CHANGE
|
|
|
|
@staticmethod
|
|
def has_str_content(content: str):
|
|
"""Determines whether or not the content is empty or None.
|
|
|
|
Args:
|
|
content (str): The text.
|
|
|
|
Returns:
|
|
bool: Whether or not it has content.
|
|
"""
|
|
return content is not None and len(content.strip()) > 0
|
|
|
|
@staticmethod
|
|
def get_headers() -> List[str]:
|
|
"""Returns the csv headers to insert when serializing a list of ItemChange objects to csv.
|
|
|
|
Returns:
|
|
List[str]: The column headers
|
|
"""
|
|
return ['Relative Path', 'Key', 'Change Type', 'Previous Value', 'Current Value']
|
|
|
|
def get_row(self) -> List[str]:
|
|
"""Returns the list of values to be entered as a row in csv serialization.
|
|
|
|
Returns:
|
|
List[str]: The list of values to be entered as a row in csv serialization.
|
|
"""
|
|
return [
|
|
self.rel_path,
|
|
self.key,
|
|
self.type,
|
|
self.prev_val,
|
|
self.cur_val]
|
|
|
|
|
|
def get_item_change(rel_path: str, key: str, prev_val: str, cur_val: str) -> Union[ItemChange, None]:
|
|
"""Returns an ItemChange object if the previous value is not equal to the current value.
|
|
|
|
Args:
|
|
rel_path (str): The relative path for the properties file.
|
|
key (str): The key within the properties file for this potential change.
|
|
prev_val (str): The previous value.
|
|
cur_val (str): The current value.
|
|
|
|
Returns:
|
|
ItemChange: The ItemChange object or None if values are the same.
|
|
"""
|
|
if prev_val == cur_val:
|
|
return None
|
|
else:
|
|
return ItemChange(rel_path, key, prev_val, cur_val)
|
|
|
|
|
|
def get_changed(rel_path: str, a_str: str, b_str: str) -> Iterator[ItemChange]:
|
|
"""Given the relative path of the properties file that has been provided,
|
|
determines the property items that have changed between the two property
|
|
file strings.
|
|
|
|
Args:
|
|
rel_path (str): The relative path for the properties file.
|
|
a_str (str): The string representing the original state of the file.
|
|
b_str (str): The string representing the current state of the file.
|
|
|
|
Returns:
|
|
List[ItemChange]: The changes determined.
|
|
"""
|
|
print('Retrieving changes for {0}...'.format(rel_path))
|
|
a_dict = get_entry_dict(a_str)
|
|
b_dict = get_entry_dict(b_str)
|
|
all_keys = set().union(a_dict.keys(), b_dict.keys())
|
|
mapped = map(lambda key: get_item_change(
|
|
rel_path, key, a_dict.get(key), b_dict.get(key)), all_keys)
|
|
return filter(lambda entry: entry is not None, mapped)
|
|
|
|
|
|
class ItemChangeTest(unittest.TestCase):
|
|
@staticmethod
|
|
def dict_to_prop_str(dict: Dict[str,str]) -> str:
|
|
toret = ''
|
|
for key,val in dict.items:
|
|
toret += "{key}={value}\n".format(key=key,val=val)
|
|
|
|
return toret
|
|
|
|
def get_changed_test(self):
|
|
deleted_key = 'deleted.property.key'
|
|
deleted_val = 'will be deleted'
|
|
|
|
change_key = 'change.property.key'
|
|
change_val_a = 'original value'
|
|
change_val_b = 'new value'
|
|
|
|
change_key2 = 'change2.property.key'
|
|
change_val2_a = 'original value 2'
|
|
change_val2_b = ''
|
|
|
|
addition_key = 'addition.property.key'
|
|
addition_new_val = 'the added value'
|
|
|
|
same_key = 'samevalue.property.key'
|
|
same_value = 'the same value'
|
|
|
|
same_key2 = 'samevalue2.property.key'
|
|
same_value2 = ''
|
|
|
|
a_dict = {
|
|
deleted_key: deleted_val,
|
|
change_key: change_val_a,
|
|
change_key2: change_val2_a,
|
|
same_key: same_value,
|
|
same_key2: same_value2
|
|
}
|
|
|
|
b_dict = {
|
|
change_key: change_val_b,
|
|
change_key2: change_val2_b,
|
|
addition_key: addition_new_val,
|
|
same_key: same_value,
|
|
same_key2: same_value2
|
|
}
|
|
|
|
a_str = ItemChangeTest.dict_to_prop_str(a_dict)
|
|
b_str = ItemChangeTest.dict_to_prop_str(b_dict)
|
|
|
|
rel_path = 'my/rel/path.properties'
|
|
|
|
key_to_change = {}
|
|
|
|
for item_change in get_changed(rel_path, a_str, b_str):
|
|
self.assertEqual(item_change.rel_path, rel_path)
|
|
key_to_change[item_change.key] = item_change
|
|
|
|
deleted_item = key_to_change[deleted_key]
|
|
self.assertEqual(deleted_item.type, ChangeType.DELETION)
|
|
self.assertEqual(deleted_item.prev_val, deleted_val)
|
|
self.assertEqual(deleted_item.cur_val, None)
|
|
|
|
addition_item = key_to_change[addition_key]
|
|
self.assertEqual(addition_item.type, ChangeType.ADDITION)
|
|
self.assertEqual(addition_item.prev_val, None)
|
|
self.assertEqual(deleted_item.cur_val, addition_new_val)
|
|
|
|
change_item = key_to_change[change_key]
|
|
self.assertEqual(change_item.type, ChangeType.CHANGE)
|
|
self.assertEqual(change_item.prev_val, change_val_a)
|
|
self.assertEqual(change_item.cur_val, change_val_b)
|
|
|
|
change_item2 = key_to_change[change_key2]
|
|
self.assertEqual(change_item2.type, ChangeType.CHANGE)
|
|
self.assertEqual(change_item2.prev_val, change_val2_a)
|
|
self.assertEqual(change_item2.cur_val, change_val2_b)
|
|
|
|
self.assertTrue(same_key not in key_to_change)
|
|
self.assertTrue(same_key2 not in key_to_change) |