test_library_print_name.py 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """Tests for library files displaying the filename, not the embedded 3MF Title (#1489).
  2. The 3MF ``<metadata name="Title">`` is the in-app project title — generic
  3. ("Exported 3D Model") for a Bambu Studio "Save As", a marketing title for a
  4. MakerWorld download — never the filename the user saved as. The FileManager
  5. keyed its display name / search / sort off ``file_metadata.print_name``, so
  6. storing the Title made every card show the wrong name. ``_without_print_name``
  7. strips it on import; ``_migrate_drop_library_print_name`` clears it from rows
  8. imported before the fix.
  9. """
  10. import pytest
  11. from sqlalchemy import select
  12. from backend.app.api.routes.library import _without_print_name
  13. from backend.app.core.database import _migrate_drop_library_print_name
  14. from backend.app.models.library import LibraryFile
  15. # --- _without_print_name ---------------------------------------------------
  16. def test_strips_print_name_keeps_siblings():
  17. cleaned = _without_print_name({"print_name": "Exported 3D Model", "print_time_seconds": 100})
  18. assert cleaned == {"print_time_seconds": 100}
  19. def test_none_passes_through():
  20. assert _without_print_name(None) is None
  21. def test_dict_without_print_name_returned_unchanged():
  22. meta = {"print_time_seconds": 50}
  23. # No copy needed when there's nothing to strip — same object back.
  24. assert _without_print_name(meta) is meta
  25. def test_does_not_mutate_input():
  26. original = {"print_name": "Whatever", "filament_used_grams": 12}
  27. cleaned = _without_print_name(original)
  28. assert original == {"print_name": "Whatever", "filament_used_grams": 12} # untouched
  29. assert cleaned == {"filament_used_grams": 12}
  30. def test_print_name_only_collapses_to_empty_dict():
  31. assert _without_print_name({"print_name": "Exported 3D Model"}) == {}
  32. # --- _migrate_drop_library_print_name --------------------------------------
  33. @pytest.mark.sqlite_only # pins the SQLite branch of the migration
  34. async def test_migration_strips_print_name_from_existing_rows(db_session, monkeypatch):
  35. """Rows imported before the fix get print_name cleared; siblings and rows
  36. that never had it are untouched. Idempotent on a second run.
  37. The test DB is SQLite; is_sqlite() reads settings.database_url (not the
  38. test engine), so pin it to exercise the SQLite branch deterministically.
  39. The PostgreSQL branch is verified against a real PG instance separately."""
  40. monkeypatch.setattr("backend.app.core.database.is_sqlite", lambda: True)
  41. db_session.add_all(
  42. [
  43. LibraryFile(
  44. filename="halloween.3mf",
  45. file_path="/a",
  46. file_type="3mf",
  47. file_size=1,
  48. file_metadata={"print_name": "Haunted House", "print_time_seconds": 100},
  49. ),
  50. LibraryFile(
  51. filename="no_meta.3mf",
  52. file_path="/b",
  53. file_type="3mf",
  54. file_size=1,
  55. file_metadata={"print_time_seconds": 50},
  56. ),
  57. LibraryFile(
  58. filename="null_meta.3mf",
  59. file_path="/c",
  60. file_type="3mf",
  61. file_size=1,
  62. file_metadata=None,
  63. ),
  64. ]
  65. )
  66. await db_session.commit()
  67. conn = await db_session.connection()
  68. await _migrate_drop_library_print_name(conn)
  69. await _migrate_drop_library_print_name(conn) # idempotent
  70. db_session.expire_all()
  71. rows = (await db_session.execute(select(LibraryFile).order_by(LibraryFile.filename))).scalars().all()
  72. by_name = {r.filename: r for r in rows}
  73. assert by_name["halloween.3mf"].file_metadata == {"print_time_seconds": 100}
  74. assert by_name["no_meta.3mf"].file_metadata == {"print_time_seconds": 50}
  75. assert by_name["null_meta.3mf"].file_metadata is None