Files
Artemis-Eapil/tests/unit/utils/test_notes.py
T
chenmingxuan e1ea099592 feat: add official Codex skill and harden task execution
Install and update artemis-use with task diagnostics and plugin guidance. Preserve cross-device file receipts, review canonical reports, guard stage transitions and reduce small history summaries. Improve exploration lifecycle, request recovery and browser live connections.
2026-10-18 14:18:37 +08:00

189 lines
6.7 KiB
Python

# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from artemis.utils.notes import (
append_note_content,
list_notes_info,
read_note_content,
save_note_content,
save_verified_note,
update_note_content,
)
import pytest
@pytest.mark.parametrize("content", ["# 报告\n结果\n", "line\r\nsecond", ""])
def test_verified_note_receipt_matches_actual_file_bytes(tmp_path, content):
import hashlib
receipt = save_verified_note(tmp_path, "report.md", content)
data = (tmp_path / receipt["path"]).read_bytes()
assert receipt["path"] == "notes/report.md"
assert receipt["verified"] is True and receipt["bytes"] == len(data)
assert receipt["sha256"] == hashlib.sha256(data).hexdigest()
def test_verified_note_does_not_confirm_incomplete_write(tmp_path, monkeypatch):
from artemis.utils import notes
def partial_write(base_dir, key, content):
save_note_content(base_dir, key, content[:1])
monkeypatch.setattr(notes, "save_note_content", partial_write)
with pytest.raises(OSError, match="读回不一致"):
save_verified_note(tmp_path, "report", "完整报告")
def test_list_notes_info(tmp_path):
base_dir = tmp_path
# Create some notes
save_note_content(base_dir, "note1", "line1\nline2\nline3")
save_note_content(base_dir, "note2", "line1\nline2")
info = list_notes_info(base_dir)
assert info == {"note1": 3, "note2": 2}
def test_read_note_content_range(tmp_path):
base_dir = tmp_path
save_note_content(base_dir, "note1", "line1\nline2\nline3\nline4")
# Read full
assert read_note_content(base_dir, "note1") == "line1\nline2\nline3\nline4"
# Read range
assert read_note_content(base_dir, "note1", start_line=2, end_line=3) == "line2\nline3"
# Read from start to line
assert read_note_content(base_dir, "note1", end_line=2) == "line1\nline2"
# Read from line to end
assert read_note_content(base_dir, "note1", start_line=3) == "line3\nline4"
def test_update_note_exact_match(tmp_path):
base_dir = tmp_path
original_content = 'def demo():\n print("Hello, World!")\n return True\n'
save_note_content(base_dir, "task_plan", original_content)
# Exact match
warning = update_note_content(
base_dir,
"task_plan",
' print("Hello, World!")',
' print("Hello, Jetski!")',
)
assert warning is None
updated_content = read_note_content(base_dir, "task_plan")
assert 'print("Hello, Jetski!")' in updated_content
assert 'print("Hello, World!")' not in updated_content
def test_update_note_relaxed_match(tmp_path):
base_dir = tmp_path
# Multi-line content with checkboxes and indentation
original_content = (
"- [ ] Step 1: Research the issue\n - [ ] Step 2: Write code\n - [ ] Step 3: Run tests\n"
)
save_note_content(base_dir, "task_plan", original_content)
# Relaxed match: case difference, quote difference, checkbox bullet difference, trailing whitespace
target = " * [ ] step 2: write code "
replacement = " - [/] Step 2: In progress"
warning = update_note_content(base_dir, "task_plan", target, replacement)
# Warning should be returned
assert warning is not None
assert "We did our best to apply changes despite some inaccuracies" in warning
updated_content = read_note_content(base_dir, "task_plan")
assert "Step 2: In progress" in updated_content
assert "Step 2: Write code" not in updated_content
# Check indentation is preserved from replacement
assert " - [/] Step 2: In progress\n" in updated_content
def test_update_note_fuzzy_match(tmp_path):
base_dir = tmp_path
original_content = 'print("Alpha message")\nprint("Gamma message")\nprint("Delta message")\n'
save_note_content(base_dir, "task_plan", original_content)
# Fuzzy match: typo (Gemma vs Gamma)
target = 'print("Gemma message")'
replacement = 'print("Gamma updated!")'
warning = update_note_content(base_dir, "task_plan", target, replacement)
assert warning is not None
assert "We did our best to apply changes despite some inaccuracies" in warning
updated_content = read_note_content(base_dir, "task_plan")
assert 'print("Gamma updated!")' in updated_content
assert 'print("Gamma message")' not in updated_content
def test_update_note_ambiguous_match(tmp_path):
base_dir = tmp_path
# Multiple lines that could match target
original_content = 'print("Beta message")\nprint("Zeta message")\nprint("Eta message")\n'
save_note_content(base_dir, "task_plan", original_content)
# Target is highly ambiguous (Xeta is almost equally close to Beta and Zeta)
target = 'print("Xeta message")'
replacement = 'print("Ambiguous match!")'
# Should raise ValueError due to ambiguity or inability to find unique match
with pytest.raises(ValueError) as exc_info:
update_note_content(base_dir, "task_plan", target, replacement)
assert "Target string 'print(\"Xeta message\")' not found" in str(
exc_info.value
) or "not unique" in str(exc_info.value)
def test_update_note_not_found(tmp_path):
base_dir = tmp_path
original_content = 'print("Alpha message")\n'
save_note_content(base_dir, "task_plan", original_content)
# Totally different target
target = 'print("Something totally different")'
replacement = 'print("Hello")'
with pytest.raises(ValueError) as exc_info:
update_note_content(base_dir, "task_plan", target, replacement)
assert "not found" in str(exc_info.value)
def test_append_note_content(tmp_path):
base_dir = tmp_path
# Case 1: File does not exist
append_note_content(base_dir, "new_note", "hello")
assert read_note_content(base_dir, "new_note") == "hello\n"
# Case 2: File exists and ends with a newline
append_note_content(base_dir, "new_note", "world")
assert read_note_content(base_dir, "new_note") == "hello\nworld\n"
# Case 3: File exists and does not end with a newline
file_path = base_dir / "notes" / "no_newline.md"
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text("no newline", encoding="utf-8")
append_note_content(base_dir, "no_newline", "added text")
assert read_note_content(base_dir, "no_newline") == "no newline\nadded text\n"