Skip to content

Commit

Permalink
Tests for match_name()
Browse files Browse the repository at this point in the history
  • Loading branch information
disinvite committed Jan 18, 2025
1 parent 3ce5302 commit 33b1541
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 8 deletions.
30 changes: 22 additions & 8 deletions reccmp/isledecomp/compare/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,35 @@ def matched(self) -> bool:
def get(self, key: str, default: Any = None) -> Any:
return self.options.get(key, default)

def best_name(self) -> str | None:
"""Return the first name that exists from our
priority list of name attributes for this entity."""
for key in ("computed_name", "name"):
if (value := self.options.get(key)) is not None:
return str(value)

return None

def match_name(self) -> str | None:
"""Combination of the name and compare type.
Intended for name substitution in the diff. If there is a diff,
it will be more obvious what this symbol indicates."""
best_name: str
for key in ("computed_name", "name"):
if (value := self.options.get(key)) is not None:
best_name = str(value)
break
else:

# Special handling for strings that might contain newlines.
if self.entity_type == EntityType.STRING:
if self.name is not None:
# Escape newlines so they do not interfere
# with asm sanitize and diff calculation.
return f"{repr(self.name)} (STRING)"

return None

best_name = self.best_name()
if best_name is None:
return None

ctype = EntityTypeLookup.get(self.entity_type or -1, "UNK")
name = repr(self.name) if self.entity_type == EntityType.STRING else best_name
return f"{name} ({ctype})"
return f"{best_name} ({ctype})"

def offset_name(self, ofs: int) -> str | None:
if self.name is None:
Expand Down
66 changes: 66 additions & 0 deletions tests/test_entity_obj.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Tests related to the ReccmpEntity ORM object"""

import json
from reccmp.isledecomp.types import EntityType
from reccmp.isledecomp.compare.db import ReccmpEntity


def create_entity(
orig_addr: int | None, recomp_addr: int | None, **kwargs
) -> ReccmpEntity:
"""Helper to create the JSON string representation of the key/value args."""
return ReccmpEntity(orig_addr, recomp_addr, json.dumps(kwargs))


def test_match_name_none():
"""match_name() returns None if there are no name attributes"""
assert create_entity(100, 200).match_name() is None


def test_match_name_no_type():
"""If we have a name, the entity_type is included in the match_name().
If type is None, the type string is 'UNK'"""
e = create_entity(100, 200, name="Test")
assert "Test" in e.match_name()
assert "UNK" in e.match_name()


def test_match_name_with_type():
"""Use all-caps representation of entity type in the match name"""
e = create_entity(100, 200, type=EntityType.FUNCTION, name="Test")
assert "Test" in e.match_name()
assert "FUNCTION" in e.match_name()


def test_match_name_computed_name():
"""Use the 'computed_name' field if present"""
e = create_entity(100, 200, computed_name="Hello")
assert "Hello" in e.match_name()


def test_match_name_priority():
"""Prefer 'computed_name' over 'name'"""
e = create_entity(100, 200, computed_name="Hello", name="Test")
assert "Hello" in e.match_name()


def test_computed_name_string():
"""Ignore 'computed_name' if entity is a string"""

e = create_entity(
100, 200, computed_name="Hello", name="Test", type=EntityType.STRING
)
assert "Test" in e.match_name()


def test_match_name_string():
"""We currently store the string value in the name field.
If the string includes newlines, we need to escape them before replacing the
value during asm sanitize. (It will interfere with diff calculation.)"""
string = """A string
with
newlines"""

e = create_entity(100, None, type=EntityType.STRING, name=string)
assert "\n" not in e.match_name()
assert "\\n" in e.match_name()

0 comments on commit 33b1541

Please sign in to comment.