mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 02:31:45 +01:00
feat: improve content_hash calculation
This commit is contained in:
committed by
Sebastian Thomschke
parent
f1cd597dd8
commit
85a5cf5224
39
tests/unit/test_ad_model.py
Normal file
39
tests/unit/test_ad_model.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# SPDX-FileCopyrightText: © Sebastian Thomschke and contributors
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
||||
from kleinanzeigen_bot.model.ad_model import AdPartial
|
||||
|
||||
|
||||
def test_update_content_hash() -> None:
|
||||
minimal_ad_cfg = {
|
||||
"id": "123456789",
|
||||
"title": "Test Ad Title",
|
||||
"category": "160",
|
||||
"description": "Test Description",
|
||||
}
|
||||
minimal_ad_cfg_hash = "ae3defaccd6b41f379eb8de17263caa1bd306e35e74b11aa03a4738621e96ece"
|
||||
|
||||
assert AdPartial.model_validate(minimal_ad_cfg).update_content_hash().content_hash == minimal_ad_cfg_hash
|
||||
|
||||
assert AdPartial.model_validate(minimal_ad_cfg | {
|
||||
"id": "123456789",
|
||||
"created_on": "2025-05-08T09:34:03",
|
||||
"updated_on": "2025-05-14T20:43:16",
|
||||
"content_hash": "5753ead7cf42b0ace5fe658ecb930b3a8f57ef49bd52b7ea2d64b91b2c75517e"
|
||||
}).update_content_hash().content_hash == minimal_ad_cfg_hash
|
||||
|
||||
assert AdPartial.model_validate(minimal_ad_cfg | {
|
||||
"active": None,
|
||||
"images": None,
|
||||
"shipping_options": None,
|
||||
"special_attributes": None,
|
||||
"contact": None,
|
||||
}).update_content_hash().content_hash == minimal_ad_cfg_hash
|
||||
|
||||
assert AdPartial.model_validate(minimal_ad_cfg | {
|
||||
"active": True,
|
||||
"images": [],
|
||||
"shipping_options": [],
|
||||
"special_attributes": {},
|
||||
"contact": {},
|
||||
}).update_content_hash().content_hash != minimal_ad_cfg_hash
|
||||
@@ -1,115 +0,0 @@
|
||||
# SPDX-FileCopyrightText: © Sebastian Thomschke and contributors
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from kleinanzeigen_bot import ads
|
||||
from kleinanzeigen_bot.model.config_model import Config
|
||||
|
||||
|
||||
def test_calculate_content_hash_with_none_values() -> None:
|
||||
"""Test calculate_content_hash with None values in the ad configuration."""
|
||||
ad_cfg = {
|
||||
# Minimal configuration with None values as described in bug report
|
||||
"id": "123456789",
|
||||
"created_on": "2022-07-19T07:30:20.489289",
|
||||
"updated_on": "2025-01-22T19:46:46.735896",
|
||||
"title": "Test Ad",
|
||||
"description": "Test Description",
|
||||
"images": [None, "/path/to/image.jpg", None], # List containing None values
|
||||
"shipping_options": None, # None instead of list
|
||||
"special_attributes": None, # None instead of dictionary
|
||||
"contact": {
|
||||
"street": None # None value in contact
|
||||
}
|
||||
}
|
||||
|
||||
# Should not raise TypeError
|
||||
hash_value = ads.calculate_content_hash(ad_cfg)
|
||||
assert isinstance(hash_value, str)
|
||||
assert len(hash_value) == 64 # SHA-256 hash is 64 characters long
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("config", "prefix", "expected"), [
|
||||
# Test new flattened format - prefix
|
||||
(
|
||||
{"ad_defaults": {"description_prefix": "Hello"}},
|
||||
True,
|
||||
"Hello"
|
||||
),
|
||||
# Test new flattened format - suffix
|
||||
(
|
||||
{"ad_defaults": {"description_suffix": "Bye"}},
|
||||
False,
|
||||
"Bye"
|
||||
),
|
||||
# Test legacy nested format - prefix
|
||||
(
|
||||
{"ad_defaults": {"description": {"prefix": "Hi"}}},
|
||||
True,
|
||||
"Hi"
|
||||
),
|
||||
# Test legacy nested format - suffix
|
||||
(
|
||||
{"ad_defaults": {"description": {"suffix": "Ciao"}}},
|
||||
False,
|
||||
"Ciao"
|
||||
),
|
||||
# Test precedence (new format over legacy) - prefix
|
||||
(
|
||||
{
|
||||
"ad_defaults": {
|
||||
"description_prefix": "Hello",
|
||||
"description": {"prefix": "Hi"}
|
||||
}
|
||||
},
|
||||
True,
|
||||
"Hello"
|
||||
),
|
||||
# Test precedence (new format over legacy) - suffix
|
||||
(
|
||||
{
|
||||
"ad_defaults": {
|
||||
"description_suffix": "Bye",
|
||||
"description": {"suffix": "Ciao"}
|
||||
}
|
||||
},
|
||||
False,
|
||||
"Bye"
|
||||
),
|
||||
# Test empty config
|
||||
(
|
||||
{"ad_defaults": {}},
|
||||
True,
|
||||
""
|
||||
),
|
||||
# Test None values
|
||||
(
|
||||
{"ad_defaults": {"description_prefix": None, "description_suffix": None}},
|
||||
True,
|
||||
""
|
||||
),
|
||||
# Add test for malformed config
|
||||
(
|
||||
{}, # Empty config
|
||||
True,
|
||||
""
|
||||
),
|
||||
# Test for missing ad_defaults
|
||||
(
|
||||
{"some_other_key": {}},
|
||||
True,
|
||||
""
|
||||
),
|
||||
])
|
||||
def test_get_description_affixes(
|
||||
config:dict[str, Any],
|
||||
prefix:bool,
|
||||
expected:str,
|
||||
test_bot_config:Config
|
||||
) -> None:
|
||||
"""Test get_description_affixes function with various inputs."""
|
||||
result = ads.get_description_affixes(test_bot_config.with_values(config), prefix = prefix)
|
||||
assert result == expected
|
||||
62
tests/unit/test_config_model.py
Normal file
62
tests/unit/test_config_model.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# SPDX-FileCopyrightText: © Sebastian Thomschke and contributors
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
||||
from kleinanzeigen_bot.model.config_model import AdDefaults
|
||||
|
||||
|
||||
def test_migrate_legacy_description_prefix() -> None:
|
||||
assert AdDefaults.model_validate({
|
||||
}).description_prefix is None
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_prefix": "Prefix"
|
||||
}).description_prefix == "Prefix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_prefix": "Prefix",
|
||||
"description": {
|
||||
"prefix": "Legacy Prefix"
|
||||
}
|
||||
}).description_prefix == "Prefix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description": {
|
||||
"prefix": "Legacy Prefix"
|
||||
}
|
||||
}).description_prefix == "Legacy Prefix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_prefix": "",
|
||||
"description": {
|
||||
"prefix": "Legacy Prefix"
|
||||
}
|
||||
}).description_prefix == "Legacy Prefix"
|
||||
|
||||
|
||||
def test_migrate_legacy_description_suffix() -> None:
|
||||
assert AdDefaults.model_validate({
|
||||
}).description_suffix is None
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_suffix": "Suffix"
|
||||
}).description_suffix == "Suffix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_suffix": "Suffix",
|
||||
"description": {
|
||||
"suffix": "Legacy Suffix"
|
||||
}
|
||||
}).description_suffix == "Suffix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description": {
|
||||
"suffix": "Legacy Suffix"
|
||||
}
|
||||
}).description_suffix == "Legacy Suffix"
|
||||
|
||||
assert AdDefaults.model_validate({
|
||||
"description_suffix": "",
|
||||
"description": {
|
||||
"suffix": "Legacy Suffix"
|
||||
}
|
||||
}).description_suffix == "Legacy Suffix"
|
||||
@@ -14,7 +14,6 @@ from pydantic import ValidationError
|
||||
|
||||
from kleinanzeigen_bot import LOG, KleinanzeigenBot, misc
|
||||
from kleinanzeigen_bot._version import __version__
|
||||
from kleinanzeigen_bot.ads import calculate_content_hash
|
||||
from kleinanzeigen_bot.model.ad_model import Ad
|
||||
from kleinanzeigen_bot.model.config_model import AdDefaults, Config, PublishingConfig
|
||||
from kleinanzeigen_bot.utils import dicts, loggers
|
||||
@@ -844,7 +843,7 @@ class TestKleinanzeigenBotAdRepublication:
|
||||
|
||||
# Calculate hash before making the copy to ensure they match
|
||||
ad_cfg_orig = ad_cfg.model_dump()
|
||||
current_hash = calculate_content_hash(ad_cfg_orig)
|
||||
current_hash = ad_cfg.update_content_hash().content_hash
|
||||
ad_cfg_orig["content_hash"] = current_hash
|
||||
|
||||
# Mock the config to prevent actual file operations
|
||||
@@ -874,8 +873,8 @@ class TestKleinanzeigenBotShippingOptions:
|
||||
})
|
||||
|
||||
# Create the original ad config and published ads list
|
||||
ad_cfg.update_content_hash() # Add content hash to prevent republication
|
||||
ad_cfg_orig = ad_cfg.model_dump()
|
||||
ad_cfg_orig["content_hash"] = calculate_content_hash(ad_cfg_orig) # Add content hash to prevent republication
|
||||
published_ads:list[dict[str, Any]] = []
|
||||
|
||||
# Set up default config values needed for the test
|
||||
@@ -1155,7 +1154,7 @@ class TestKleinanzeigenBotChangedAds:
|
||||
# Calculate hash for changed_ad and add it to the config
|
||||
# Then modify the ad to simulate a change
|
||||
changed_ad = ad_cfg.model_dump()
|
||||
changed_hash = calculate_content_hash(changed_ad)
|
||||
changed_hash = ad_cfg.update_content_hash().content_hash
|
||||
changed_ad["content_hash"] = changed_hash
|
||||
# Now modify the ad to make it "changed"
|
||||
changed_ad["title"] = "Changed Ad - Modified"
|
||||
|
||||
Reference in New Issue
Block a user