Tags working
This commit is contained in:
parent
3263788415
commit
f6e10dccac
11 changed files with 1148 additions and 267 deletions
781
tests/test_tags.py
Normal file
781
tests/test_tags.py
Normal file
|
|
@ -0,0 +1,781 @@
|
|||
from bouquin.db import DBManager
|
||||
from bouquin.tags_widget import PageTagsWidget, TagChip
|
||||
from bouquin.tag_browser import TagBrowserDialog
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# DB Layer Tag Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_set_tags_for_page_creates_tags(fresh_db):
|
||||
"""Test that setting tags for a page creates the tags in the database"""
|
||||
date_iso = "2024-01-15"
|
||||
tags = ["work", "important", "meeting"]
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, tags)
|
||||
|
||||
# Verify tags were created
|
||||
all_tags = fresh_db.list_tags()
|
||||
tag_names = [name for _, name, _ in all_tags]
|
||||
|
||||
assert "work" in tag_names
|
||||
assert "important" in tag_names
|
||||
assert "meeting" in tag_names
|
||||
|
||||
|
||||
def test_get_tags_for_page(fresh_db):
|
||||
"""Test retrieving tags for a specific page"""
|
||||
date_iso = "2024-01-15"
|
||||
tags = ["work", "important"]
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, tags)
|
||||
retrieved_tags = fresh_db.get_tags_for_page(date_iso)
|
||||
|
||||
assert len(retrieved_tags) == 2
|
||||
tag_names = [name for _, name, _ in retrieved_tags]
|
||||
assert "work" in tag_names
|
||||
assert "important" in tag_names
|
||||
|
||||
|
||||
def test_tags_have_colors(fresh_db):
|
||||
"""Test that created tags have default colors assigned"""
|
||||
date_iso = "2024-01-15"
|
||||
fresh_db.set_tags_for_page(date_iso, ["test"])
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
tag_id, name, color = tags[0]
|
||||
|
||||
assert color.startswith("#")
|
||||
assert len(color) in (4, 7) # #RGB or #RRGGBB
|
||||
|
||||
|
||||
def test_set_tags_replaces_existing(fresh_db):
|
||||
"""Test that setting tags replaces the existing tag set"""
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["old1", "old2"])
|
||||
fresh_db.set_tags_for_page(date_iso, ["new1", "new2"])
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
tag_names = [name for _, name, _ in tags]
|
||||
|
||||
assert "new1" in tag_names
|
||||
assert "new2" in tag_names
|
||||
assert "old1" not in tag_names
|
||||
assert "old2" not in tag_names
|
||||
|
||||
|
||||
def test_set_tags_empty_clears_tags(fresh_db):
|
||||
"""Test that setting empty tag list clears all tags for page"""
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["tag1", "tag2"])
|
||||
fresh_db.set_tags_for_page(date_iso, [])
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 0
|
||||
|
||||
|
||||
def test_tags_case_insensitive_deduplication(fresh_db):
|
||||
"""Test that tags are deduplicated case-insensitively"""
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
# Try to set tags with different cases
|
||||
fresh_db.set_tags_for_page(date_iso, ["Work", "work", "WORK"])
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
|
||||
|
||||
def test_tags_case_insensitive_reuse(fresh_db):
|
||||
"""Test that existing tags are reused regardless of case"""
|
||||
date1 = "2024-01-15"
|
||||
date2 = "2024-01-16"
|
||||
|
||||
# Create tag with lowercase
|
||||
fresh_db.set_tags_for_page(date1, ["work"])
|
||||
|
||||
# Try to add same tag with different case on different page
|
||||
fresh_db.set_tags_for_page(date2, ["Work"])
|
||||
|
||||
# Should reuse the existing tag
|
||||
all_tags = fresh_db.list_tags()
|
||||
work_tags = [t for t in all_tags if t[1].lower() == "work"]
|
||||
assert len(work_tags) == 1 # Only one "work" tag should exist
|
||||
|
||||
|
||||
def test_tags_whitespace_normalization(fresh_db):
|
||||
"""Test that tags are trimmed and empty strings ignored"""
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, [" work ", "", " ", "meeting"])
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
tag_names = [name for _, name, _ in tags]
|
||||
|
||||
assert "work" in tag_names
|
||||
assert "meeting" in tag_names
|
||||
assert len(tags) == 2 # Empty strings should be filtered
|
||||
|
||||
|
||||
def test_list_all_tags(fresh_db):
|
||||
"""Test listing all tags in the database"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["tag1", "tag2"])
|
||||
fresh_db.set_tags_for_page("2024-01-16", ["tag2", "tag3"])
|
||||
|
||||
all_tags = fresh_db.list_tags()
|
||||
tag_names = [name for _, name, _ in all_tags]
|
||||
|
||||
assert len(all_tags) == 3
|
||||
assert "tag1" in tag_names
|
||||
assert "tag2" in tag_names
|
||||
assert "tag3" in tag_names
|
||||
|
||||
|
||||
def test_update_tag_name_and_color(fresh_db):
|
||||
"""Test updating a tag's name and color"""
|
||||
date_iso = "2024-01-15"
|
||||
fresh_db.set_tags_for_page(date_iso, ["oldname"])
|
||||
|
||||
tags = fresh_db.list_tags()
|
||||
tag_id = tags[0][0]
|
||||
|
||||
fresh_db.update_tag(tag_id, "newname", "#FF0000")
|
||||
|
||||
updated_tags = fresh_db.list_tags()
|
||||
assert len(updated_tags) == 1
|
||||
assert updated_tags[0][1] == "newname"
|
||||
assert updated_tags[0][2] == "#FF0000"
|
||||
|
||||
|
||||
def test_delete_tag(fresh_db):
|
||||
"""Test deleting a tag removes it globally"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["tag1", "tag2"])
|
||||
fresh_db.set_tags_for_page("2024-01-16", ["tag1"])
|
||||
|
||||
tags = fresh_db.list_tags()
|
||||
tag1_id = [tid for tid, name, _ in tags if name == "tag1"][0]
|
||||
|
||||
fresh_db.delete_tag(tag1_id)
|
||||
|
||||
# Tag should be removed from all pages
|
||||
tags_page1 = fresh_db.get_tags_for_page("2024-01-15")
|
||||
tags_page2 = fresh_db.get_tags_for_page("2024-01-16")
|
||||
|
||||
assert len(tags_page1) == 1
|
||||
assert tags_page1[0][1] == "tag2"
|
||||
assert len(tags_page2) == 0
|
||||
|
||||
|
||||
def test_get_pages_for_tag(fresh_db):
|
||||
"""Test retrieving all pages that have a specific tag"""
|
||||
fresh_db.save_new_version("2024-01-15", "Content 1", "note")
|
||||
fresh_db.save_new_version("2024-01-16", "Content 2", "note")
|
||||
fresh_db.save_new_version("2024-01-17", "Content 3", "note")
|
||||
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["work"])
|
||||
fresh_db.set_tags_for_page("2024-01-16", ["work", "meeting"])
|
||||
fresh_db.set_tags_for_page("2024-01-17", ["personal"])
|
||||
|
||||
pages = fresh_db.get_pages_for_tag("work")
|
||||
dates = [date_iso for date_iso, _ in pages]
|
||||
|
||||
assert "2024-01-15" in dates
|
||||
assert "2024-01-16" in dates
|
||||
assert "2024-01-17" not in dates
|
||||
|
||||
|
||||
def test_tags_persist_across_reconnect(fresh_db, tmp_db_cfg):
|
||||
"""Test that tags persist when database is closed and reopened"""
|
||||
date_iso = "2024-01-15"
|
||||
fresh_db.set_tags_for_page(date_iso, ["persistent", "tag"])
|
||||
fresh_db.close()
|
||||
|
||||
# Reopen database
|
||||
db2 = DBManager(tmp_db_cfg)
|
||||
assert db2.connect()
|
||||
|
||||
tags = db2.get_tags_for_page(date_iso)
|
||||
tag_names = [name for _, name, _ in tags]
|
||||
|
||||
assert "persistent" in tag_names
|
||||
assert "tag" in tag_names
|
||||
db2.close()
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# PageTagsWidget Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_page_tags_widget_creation(app, fresh_db):
|
||||
"""Test that PageTagsWidget can be created"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
assert widget is not None
|
||||
assert widget._db == fresh_db
|
||||
|
||||
|
||||
def test_page_tags_widget_set_current_date(app, fresh_db):
|
||||
"""Test setting the current date on the widget"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["test"])
|
||||
widget.set_current_date(date_iso)
|
||||
|
||||
assert widget._current_date == date_iso
|
||||
|
||||
|
||||
def test_page_tags_widget_hidden_when_collapsed(app, fresh_db):
|
||||
"""Test that tag chips are hidden when widget is collapsed"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["tag1", "tag2"])
|
||||
widget.set_current_date(date_iso)
|
||||
|
||||
# Body should be hidden when collapsed
|
||||
assert not widget.body.isVisible()
|
||||
assert not widget.toggle_btn.isChecked()
|
||||
|
||||
|
||||
def test_page_tags_widget_shows_tags_when_expanded(app, fresh_db):
|
||||
"""Test that tags are shown when widget is expanded"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
widget.show() # Widget needs to be shown for visibility to work
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["tag1", "tag2"])
|
||||
widget.set_current_date(date_iso)
|
||||
|
||||
# Expand the widget
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
assert widget.body.isVisible()
|
||||
assert widget.chip_layout.count() == 2
|
||||
|
||||
|
||||
def test_page_tags_widget_add_tag(app, fresh_db):
|
||||
"""Test adding a tag through the widget"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Simulate adding a tag
|
||||
widget.add_edit.setText("newtag")
|
||||
widget._on_add_tag()
|
||||
|
||||
# Verify tag was added
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
tag_names = [name for _, name, _ in tags]
|
||||
assert "newtag" in tag_names
|
||||
|
||||
|
||||
def test_page_tags_widget_prevents_duplicates(app, fresh_db):
|
||||
"""Test that duplicate tags are prevented"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["existing"])
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Try to add the same tag
|
||||
widget.add_edit.setText("existing")
|
||||
widget._on_add_tag()
|
||||
|
||||
# Should still only have one tag
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
|
||||
|
||||
def test_page_tags_widget_case_insensitive_duplicates(app, fresh_db):
|
||||
"""Test that duplicate checking is case-insensitive"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["Test"])
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Try to add with different case
|
||||
widget.add_edit.setText("test")
|
||||
widget._on_add_tag()
|
||||
|
||||
# Should still only have one tag
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
|
||||
|
||||
def test_page_tags_widget_remove_tag(app, fresh_db):
|
||||
"""Test removing a tag through the widget"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["tag1", "tag2"])
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Get the first tag's ID
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
tag_id = tags[0][0]
|
||||
|
||||
# Remove it
|
||||
widget._remove_tag(tag_id)
|
||||
|
||||
# Verify tag was removed
|
||||
remaining_tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(remaining_tags) == 1
|
||||
|
||||
|
||||
def test_page_tags_widget_empty_input_ignored(app, fresh_db):
|
||||
"""Test that empty tag input is ignored"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Try to add empty tag
|
||||
widget.add_edit.setText("")
|
||||
widget._on_add_tag()
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 0
|
||||
|
||||
|
||||
def test_page_tags_widget_whitespace_trimmed(app, fresh_db):
|
||||
"""Test that whitespace is trimmed from tags"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
# Add tag with whitespace
|
||||
widget.add_edit.setText(" spaced ")
|
||||
widget._on_add_tag()
|
||||
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert tags[0][1] == "spaced"
|
||||
|
||||
|
||||
def test_page_tags_widget_autocomplete_setup(app, fresh_db):
|
||||
"""Test that autocomplete is set up with existing tags"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
|
||||
# Create some tags
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["alpha", "beta", "gamma"])
|
||||
|
||||
# Setup autocomplete
|
||||
widget._setup_autocomplete()
|
||||
|
||||
completer = widget.add_edit.completer()
|
||||
assert completer is not None
|
||||
|
||||
# Check that model contains the tags
|
||||
model = completer.model()
|
||||
items = [model.index(i, 0).data() for i in range(model.rowCount())]
|
||||
assert "alpha" in items
|
||||
assert "beta" in items
|
||||
assert "gamma" in items
|
||||
|
||||
|
||||
def test_page_tags_widget_signal_tag_added(app, fresh_db):
|
||||
"""Test that tagAdded signal is emitted when tag is added"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
widget.set_current_date(date_iso)
|
||||
|
||||
signal_emitted = {"emitted": False}
|
||||
|
||||
def on_tag_added():
|
||||
signal_emitted["emitted"] = True
|
||||
|
||||
widget.tagAdded.connect(on_tag_added)
|
||||
|
||||
widget.add_edit.setText("testtag")
|
||||
widget._on_add_tag()
|
||||
|
||||
assert signal_emitted["emitted"]
|
||||
|
||||
|
||||
def test_page_tags_widget_signal_tag_activated(app, fresh_db):
|
||||
"""Test that tagActivated signal is emitted when tag is clicked"""
|
||||
widget = PageTagsWidget(fresh_db)
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
fresh_db.set_tags_for_page(date_iso, ["clickable"])
|
||||
widget.set_current_date(date_iso)
|
||||
widget.toggle_btn.setChecked(True)
|
||||
widget._on_toggle(True)
|
||||
|
||||
signal_data = {"tag_name": None}
|
||||
|
||||
def on_tag_activated(name):
|
||||
signal_data["tag_name"] = name
|
||||
|
||||
widget.tagActivated.connect(on_tag_activated)
|
||||
widget._on_chip_clicked("clickable")
|
||||
|
||||
assert signal_data["tag_name"] == "clickable"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# TagChip Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_tag_chip_creation(app):
|
||||
"""Test that TagChip can be created"""
|
||||
chip = TagChip(1, "test", "#FF0000")
|
||||
assert chip is not None
|
||||
assert chip.tag_id == 1
|
||||
|
||||
|
||||
def test_tag_chip_with_remove_button(app):
|
||||
"""Test TagChip with remove button"""
|
||||
chip = TagChip(1, "test", "#FF0000", show_remove=True)
|
||||
|
||||
# Find the remove button (should be a QToolButton with text "×")
|
||||
buttons = chip.findChildren(object)
|
||||
assert any(hasattr(b, "text") and b.text() == "×" for b in buttons)
|
||||
|
||||
|
||||
def test_tag_chip_without_remove_button(app):
|
||||
"""Test TagChip without remove button"""
|
||||
chip = TagChip(1, "test", "#FF0000", show_remove=False)
|
||||
|
||||
# Should not have remove button
|
||||
buttons = chip.findChildren(object)
|
||||
assert not any(hasattr(b, "text") and b.text() == "×" for b in buttons)
|
||||
|
||||
|
||||
def test_tag_chip_color_display(app):
|
||||
"""Test that TagChip displays the correct color"""
|
||||
chip = TagChip(1, "test", "#FF0000")
|
||||
|
||||
# Find the color label
|
||||
labels = chip.findChildren(object)
|
||||
color_labels = [
|
||||
l
|
||||
for l in labels
|
||||
if hasattr(l, "styleSheet") and "background-color" in str(l.styleSheet())
|
||||
]
|
||||
|
||||
assert len(color_labels) > 0
|
||||
assert (
|
||||
"#FF0000" in color_labels[0].styleSheet()
|
||||
or "rgb(255, 0, 0)" in color_labels[0].styleSheet()
|
||||
)
|
||||
|
||||
|
||||
def test_tag_chip_remove_signal(app):
|
||||
"""Test that TagChip emits removeRequested signal"""
|
||||
chip = TagChip(1, "test", "#FF0000", show_remove=True)
|
||||
|
||||
signal_data = {"tag_id": None}
|
||||
|
||||
def on_remove(tag_id):
|
||||
signal_data["tag_id"] = tag_id
|
||||
|
||||
chip.removeRequested.connect(on_remove)
|
||||
chip.removeRequested.emit(1)
|
||||
|
||||
assert signal_data["tag_id"] == 1
|
||||
|
||||
|
||||
def test_tag_chip_clicked_signal(app):
|
||||
"""Test that TagChip emits clicked signal"""
|
||||
chip = TagChip(1, "test", "#FF0000")
|
||||
|
||||
signal_data = {"tag_name": None}
|
||||
|
||||
def on_clicked(name):
|
||||
signal_data["tag_name"] = name
|
||||
|
||||
chip.clicked.connect(on_clicked)
|
||||
chip.clicked.emit("test")
|
||||
|
||||
assert signal_data["tag_name"] == "test"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# TagBrowserDialog Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_tag_browser_creation(app, fresh_db):
|
||||
"""Test that TagBrowserDialog can be created"""
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
assert dialog is not None
|
||||
|
||||
|
||||
def test_tag_browser_displays_tags(app, fresh_db):
|
||||
"""Test that TagBrowserDialog displays tags in tree"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["tag1", "tag2"])
|
||||
fresh_db.save_new_version("2024-01-15", "Content", "note")
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
# Tree should have top-level items for each tag
|
||||
assert dialog.tree.topLevelItemCount() == 2
|
||||
|
||||
|
||||
def test_tag_browser_tag_with_pages(app, fresh_db):
|
||||
"""Test that TagBrowserDialog shows pages under tags"""
|
||||
fresh_db.save_new_version("2024-01-15", "Content 1", "note")
|
||||
fresh_db.save_new_version("2024-01-16", "Content 2", "note")
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["work"])
|
||||
fresh_db.set_tags_for_page("2024-01-16", ["work"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
# Find the "work" tag item
|
||||
root = dialog.tree.topLevelItem(0)
|
||||
|
||||
# Should have 2 child items (the dates)
|
||||
assert root.childCount() == 2
|
||||
|
||||
|
||||
def test_tag_browser_focus_tag(app, fresh_db):
|
||||
"""Test that TagBrowserDialog can focus on a specific tag"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["alpha", "beta"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db, focus_tag="beta")
|
||||
|
||||
# The focused tag should be expanded and selected
|
||||
current_item = dialog.tree.currentItem()
|
||||
assert current_item is not None
|
||||
|
||||
|
||||
def test_tag_browser_color_display(app, fresh_db):
|
||||
"""Test that tags display their colors in the browser"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["colorful"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
root = dialog.tree.topLevelItem(0)
|
||||
# Color should be shown in column 1
|
||||
color_text = root.text(1)
|
||||
assert color_text.startswith("#")
|
||||
|
||||
|
||||
def test_tag_browser_edit_name_button_disabled(app, fresh_db):
|
||||
"""Test that edit button is disabled when no tag selected"""
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
assert not dialog.edit_name_btn.isEnabled()
|
||||
|
||||
|
||||
def test_tag_browser_edit_name_button_enabled(app, fresh_db):
|
||||
"""Test that edit button is enabled when tag selected"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["test"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
# Select the first item
|
||||
item = dialog.tree.topLevelItem(0)
|
||||
dialog.tree.setCurrentItem(item)
|
||||
dialog._on_item_clicked(item, 0)
|
||||
|
||||
assert dialog.edit_name_btn.isEnabled()
|
||||
|
||||
|
||||
def test_tag_browser_delete_button_state(app, fresh_db):
|
||||
"""Test that delete button state changes with selection"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["test"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
# Initially disabled
|
||||
assert not dialog.delete_btn.isEnabled()
|
||||
|
||||
# Select a tag
|
||||
item = dialog.tree.topLevelItem(0)
|
||||
dialog.tree.setCurrentItem(item)
|
||||
dialog._on_item_clicked(item, 0)
|
||||
|
||||
# Should be enabled now
|
||||
assert dialog.delete_btn.isEnabled()
|
||||
|
||||
|
||||
def test_tag_browser_change_color_button_state(app, fresh_db):
|
||||
"""Test that change color button state changes with selection"""
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["test"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
# Initially disabled
|
||||
assert not dialog.change_color_btn.isEnabled()
|
||||
|
||||
# Select a tag
|
||||
item = dialog.tree.topLevelItem(0)
|
||||
dialog.tree.setCurrentItem(item)
|
||||
dialog._on_item_clicked(item, 0)
|
||||
|
||||
# Should be enabled now
|
||||
assert dialog.change_color_btn.isEnabled()
|
||||
|
||||
|
||||
def test_tag_browser_open_date_signal(app, fresh_db):
|
||||
"""Test that clicking a date emits openDateRequested signal"""
|
||||
fresh_db.save_new_version("2024-01-15", "Content", "note")
|
||||
fresh_db.set_tags_for_page("2024-01-15", ["test"])
|
||||
|
||||
dialog = TagBrowserDialog(fresh_db)
|
||||
|
||||
signal_data = {"date": None}
|
||||
|
||||
def on_date_requested(date_iso):
|
||||
signal_data["date"] = date_iso
|
||||
|
||||
dialog.openDateRequested.connect(on_date_requested)
|
||||
|
||||
# Get the tag item and expand it
|
||||
root = dialog.tree.topLevelItem(0)
|
||||
dialog.tree.expandItem(root)
|
||||
|
||||
# Get the date child item
|
||||
date_item = root.child(0)
|
||||
|
||||
# Simulate activation
|
||||
dialog._on_item_activated(date_item, 0)
|
||||
|
||||
assert signal_data["date"] == "2024-01-15"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Integration Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_tag_workflow_end_to_end(app, fresh_db, tmp_path):
|
||||
"""Test complete tag workflow: create, list, update, delete"""
|
||||
# Create some entries with tags
|
||||
dates = ["2024-01-15", "2024-01-16", "2024-01-17"]
|
||||
for date in dates:
|
||||
fresh_db.save_new_version(date, f"Entry {date}", "note")
|
||||
|
||||
fresh_db.set_tags_for_page(dates[0], ["work", "urgent"])
|
||||
fresh_db.set_tags_for_page(dates[1], ["work", "meeting"])
|
||||
fresh_db.set_tags_for_page(dates[2], ["personal"])
|
||||
|
||||
# List all tags - should be 4 unique tags: work, urgent, meeting, personal
|
||||
all_tags = fresh_db.list_tags()
|
||||
assert len(all_tags) == 4
|
||||
|
||||
# Get pages for "work" tag
|
||||
work_pages = fresh_db.get_pages_for_tag("work")
|
||||
work_dates = [d for d, _ in work_pages]
|
||||
assert dates[0] in work_dates
|
||||
assert dates[1] in work_dates
|
||||
assert dates[2] not in work_dates
|
||||
|
||||
# Update a tag
|
||||
work_tag = [t for t in all_tags if t[1] == "work"][0]
|
||||
fresh_db.update_tag(work_tag[0], "office", "#0000FF")
|
||||
|
||||
# Verify update
|
||||
updated_tags = fresh_db.list_tags()
|
||||
office_tag = [t for t in updated_tags if t[1] == "office"][0]
|
||||
assert office_tag[2] == "#0000FF"
|
||||
|
||||
# Delete a tag
|
||||
urgent_tag = [t for t in all_tags if t[1] == "urgent"][0]
|
||||
fresh_db.delete_tag(urgent_tag[0])
|
||||
|
||||
# Verify deletion - should have 3 tags now (office, meeting, personal)
|
||||
final_tags = fresh_db.list_tags()
|
||||
tag_names = [t[1] for t in final_tags]
|
||||
assert "urgent" not in tag_names
|
||||
assert len(final_tags) == 3
|
||||
|
||||
|
||||
def test_tags_with_export(fresh_db, tmp_path):
|
||||
"""Test that tags are preserved during export operations"""
|
||||
date_iso = "2024-01-15"
|
||||
fresh_db.save_new_version(date_iso, "Content", "note")
|
||||
fresh_db.set_tags_for_page(date_iso, ["exported", "preserved"])
|
||||
|
||||
# Export to JSON
|
||||
entries = fresh_db.get_all_entries()
|
||||
json_path = tmp_path / "export.json"
|
||||
fresh_db.export_json(entries, str(json_path))
|
||||
|
||||
assert json_path.exists()
|
||||
|
||||
# Tags should still be in database
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 2
|
||||
|
||||
|
||||
def test_tags_survive_rekey(fresh_db, tmp_db_cfg):
|
||||
"""Test that tags persist after database rekey"""
|
||||
date_iso = "2024-01-15"
|
||||
fresh_db.save_new_version(date_iso, "Content", "note")
|
||||
fresh_db.set_tags_for_page(date_iso, ["persistent"])
|
||||
|
||||
# Rekey the database
|
||||
fresh_db.rekey("new-key-456")
|
||||
fresh_db.close()
|
||||
|
||||
# Reopen with new key
|
||||
tmp_db_cfg.key = "new-key-456"
|
||||
db2 = DBManager(tmp_db_cfg)
|
||||
assert db2.connect()
|
||||
|
||||
# Tags should still be there
|
||||
tags = db2.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
assert tags[0][1] == "persistent"
|
||||
db2.close()
|
||||
|
||||
|
||||
def test_multiple_pages_same_tags(fresh_db):
|
||||
"""Test multiple pages can share the same tags"""
|
||||
dates = ["2024-01-15", "2024-01-16", "2024-01-17"]
|
||||
|
||||
for date in dates:
|
||||
fresh_db.save_new_version(date, f"Content {date}", "note")
|
||||
fresh_db.set_tags_for_page(date, ["shared", "tag"])
|
||||
|
||||
# All pages should have the tags
|
||||
for date in dates:
|
||||
tags = fresh_db.get_tags_for_page(date)
|
||||
tag_names = [name for _, name, _ in tags]
|
||||
assert "shared" in tag_names
|
||||
assert "tag" in tag_names
|
||||
|
||||
# But there should only be 2 unique tags in the database
|
||||
all_tags = fresh_db.list_tags()
|
||||
assert len(all_tags) == 2
|
||||
|
||||
|
||||
def test_tag_page_without_content(fresh_db):
|
||||
"""Test that pages can have tags even without content"""
|
||||
date_iso = "2024-01-15"
|
||||
|
||||
# Set tags without saving any content
|
||||
fresh_db.set_tags_for_page(date_iso, ["tagonly"])
|
||||
|
||||
# Tags should be retrievable
|
||||
tags = fresh_db.get_tags_for_page(date_iso)
|
||||
assert len(tags) == 1
|
||||
assert tags[0][1] == "tagonly"
|
||||
|
||||
# Page should be created but with no content
|
||||
content = fresh_db.get_entry(date_iso)
|
||||
assert content is None or content == ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue