Add edge case tests for history editing feature (issue 114)
- Add test for editing a message and removing all content (empty content) - Add test for multiple consecutive edits to the same message (changes stack) - Add test for editing messages with special characters - Add test for very long message content - Add test for editing assistant messages with tool_calls - Add test for dropping all messages (empty history result) - Add test for unicode characters in message content - Add test for whitespace variations in rebase file - Add test for comments and empty lines mixed with commands - Add test for special characters and unicode in rebase content display - Fix apply_rebase to preserve original content when only role is changed - Add content_edited flag to RebaseLine to track explicit edits
This commit is contained in:
@@ -35,6 +35,7 @@ struct RebaseLine {
|
||||
size_t index;
|
||||
std::string role;
|
||||
std::string content; // For edit commands, stores the new content
|
||||
bool content_edited = false; // True if content was explicitly edited (even if empty)
|
||||
};
|
||||
|
||||
DRH_DEFINE_TYPE_MIXED(RebaseLine, (command, index, role), (content))
|
||||
|
||||
@@ -253,8 +253,8 @@ std::expected<std::vector<Message>, std::string> RebaseEngine::apply_rebase(
|
||||
// Create a copy and update role and content
|
||||
Message edited = history[i];
|
||||
edited.role = cmd->role;
|
||||
// Only update content if it was provided (non-empty means it was edited)
|
||||
if (!cmd->content.empty()) {
|
||||
// Update content only if it was explicitly edited
|
||||
if (cmd->content_edited) {
|
||||
edited.content = cmd->content;
|
||||
}
|
||||
result.push_back(std::move(edited));
|
||||
@@ -326,6 +326,7 @@ std::expected<std::vector<Message>, std::string> HistoryEditor::edit_history_int
|
||||
for (auto& line : lines) {
|
||||
if (line.index == edit_idx && line.command == RebaseCommand::Edit) {
|
||||
line.content = edit_result.value();
|
||||
line.content_edited = true; // Mark that content was explicitly edited
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -922,6 +922,533 @@ EDITEOF
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 14: Editing a message and removing all content (empty content after edit)
|
||||
test_edit_remove_all_content() {
|
||||
reset_editor_state
|
||||
local test_name="edit_remove_all_content"
|
||||
|
||||
# Create a chat file with two messages
|
||||
create_chat_file chat.json user "hello" assistant "hi there"
|
||||
|
||||
# Stage the rebase editor output (edit message 1)
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] hello
|
||||
edit 1 [assistant] hi there
|
||||
EDITEOF
|
||||
|
||||
# Stage the edit prompt response (empty content)
|
||||
cat > .editor_input_1 << 'EDITEOF'
|
||||
# Previous message:
|
||||
|
||||
[0] user: hello
|
||||
|
||||
Edit message 1 (role: assistant) below:
|
||||
|
||||
-- >8 --
|
||||
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history still has 2 messages
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "2" ]; then
|
||||
echo "FAIL: $test_name - expected 2 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify message 1 content is now empty
|
||||
local msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != "" ]; then
|
||||
echo "FAIL: $test_name - message 1 content should be empty, got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 15: Multiple consecutive edits to the same message (changes stack correctly)
|
||||
test_multiple_consecutive_edits_same_message() {
|
||||
reset_editor_state
|
||||
local test_name="multiple_consecutive_edits_same_message"
|
||||
|
||||
# Create a chat file with two messages
|
||||
create_chat_file chat.json user "hello" assistant "original"
|
||||
|
||||
# First session: Edit message 1 to change content from "original" to "first edit"
|
||||
# Staged inputs for first drharness invocation:
|
||||
# Invocation 0: rebase editor
|
||||
# Invocation 1: content editor for message 1
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] hello
|
||||
edit 1 [assistant] original
|
||||
EDITEOF
|
||||
|
||||
cat > .editor_input_1 << 'EDITEOF'
|
||||
# Previous message:
|
||||
|
||||
[0] user: hello
|
||||
|
||||
Edit message 1 (role: assistant) below:
|
||||
|
||||
-- >8 --
|
||||
first edit
|
||||
EDITEOF
|
||||
|
||||
# Staged inputs for second drharness invocation:
|
||||
# Invocation 2: rebase editor (second session)
|
||||
# Invocation 3: content editor for message 1 (second session)
|
||||
cat > .editor_input_2 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] hello
|
||||
edit 1 [assistant] first edit
|
||||
EDITEOF
|
||||
|
||||
cat > .editor_input_3 << 'EDITEOF'
|
||||
# Previous message:
|
||||
|
||||
[0] user: hello
|
||||
|
||||
Edit message 1 (role: assistant) below:
|
||||
|
||||
-- >8 --
|
||||
second edit
|
||||
EDITEOF
|
||||
|
||||
# Run first edit session
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - first edit expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify first edit was applied
|
||||
local msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != "first edit" ]; then
|
||||
echo "FAIL: $test_name - after first edit, expected 'first edit', got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run second edit session (counter continues from 2)
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - second edit expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify second edit was applied (changes stack correctly)
|
||||
msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != "second edit" ]; then
|
||||
echo "FAIL: $test_name - after second edit, expected 'second edit', got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 16: Editing messages with special characters in content
|
||||
test_edit_special_characters() {
|
||||
reset_editor_state
|
||||
local test_name="edit_special_characters"
|
||||
|
||||
# Create a chat file with special characters (quotes, dollar sign)
|
||||
create_chat_file chat.json user 'hello "quotes" and $dollar' assistant 'backslash\\here'
|
||||
|
||||
# Stage the rebase editor output (edit message 1)
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] hello "quotes" and $dollar
|
||||
edit 1 [assistant] backslash\here
|
||||
EDITEOF
|
||||
|
||||
# Stage the edit prompt response (with special characters)
|
||||
cat > .editor_input_1 << 'EDITEOF'
|
||||
# Previous message:
|
||||
|
||||
[0] user: hello "quotes" and $dollar
|
||||
|
||||
Edit message 1 (role: assistant) below:
|
||||
|
||||
-- >8 --
|
||||
edited with "quotes" and $dollar signs
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history still has 2 messages
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "2" ]; then
|
||||
echo "FAIL: $test_name - expected 2 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify message 1 content has the special characters
|
||||
local msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != 'edited with "quotes" and $dollar signs' ]; then
|
||||
echo "FAIL: $test_name - message 1 content mismatch, got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 17: Very long message content in rebase editor
|
||||
test_very_long_content() {
|
||||
reset_editor_state
|
||||
local test_name="very_long_content"
|
||||
|
||||
# Create a very long message (500 characters)
|
||||
local long_content=$(printf 'x%.0s' {1..500})
|
||||
create_chat_file chat.json user "short" assistant "$long_content"
|
||||
|
||||
# Stage the rebase editor output (pick all - just verify it handles long content)
|
||||
cat > .editor_input_0 << EDITEOF
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] short
|
||||
pick 1 [assistant] $long_content
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history still has 2 messages
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "2" ]; then
|
||||
echo "FAIL: $test_name - expected 2 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 18: Editing assistant messages that contain tool_calls
|
||||
test_edit_assistant_with_tool_calls() {
|
||||
reset_editor_state
|
||||
local test_name="edit_assistant_with_tool_calls"
|
||||
|
||||
# Create a chat file with an assistant message containing tool_calls
|
||||
cat > chat.json << 'CHATJSON'
|
||||
{
|
||||
"history": [
|
||||
{"role":"user","content":"hello"},
|
||||
{"role":"assistant","content":"calling tool","tool_calls":[{"id":"call_1","type":"function","function":{"name":"test","arguments":"{}"}}]},
|
||||
{"role":"tool","content":"result","tool_call_id":"call_1"}
|
||||
],
|
||||
"tools": []
|
||||
}
|
||||
CHATJSON
|
||||
|
||||
# Stage the rebase editor output (edit message 1)
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] hello
|
||||
edit 1 [assistant] [tool_call: test]
|
||||
drop 2 [tool] result
|
||||
EDITEOF
|
||||
|
||||
# Stage the edit prompt response (edit the content)
|
||||
cat > .editor_input_1 << 'EDITEOF'
|
||||
# Previous message:
|
||||
|
||||
[0] user: hello
|
||||
|
||||
Edit message 1 (role: assistant) below:
|
||||
|
||||
-- >8 --
|
||||
edited tool call message
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history has 2 messages (tool result dropped)
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "2" ]; then
|
||||
echo "FAIL: $test_name - expected 2 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify message 1 still has tool_calls preserved
|
||||
if ! jq -e '.history[1].tool_calls' chat.json > /dev/null 2>&1; then
|
||||
echo "FAIL: $test_name - tool_calls should be preserved"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify message 1 content was updated
|
||||
local msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != "edited tool call message" ]; then
|
||||
echo "FAIL: $test_name - message 1 content should be updated, got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 19: Dropping all messages results in empty history
|
||||
test_drop_all_messages() {
|
||||
reset_editor_state
|
||||
local test_name="drop_all_messages"
|
||||
|
||||
# Create a chat file with two messages
|
||||
create_chat_file chat.json user "hello" assistant "hi there"
|
||||
|
||||
# Stage the rebase editor output (drop all)
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
drop 0 [user] hello
|
||||
drop 1 [assistant] hi there
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history is empty
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "0" ]; then
|
||||
echo "FAIL: $test_name - expected 0 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 20: Unicode characters in message content
|
||||
test_unicode_characters() {
|
||||
reset_editor_state
|
||||
local test_name="unicode_characters"
|
||||
|
||||
# Create a chat file with unicode characters
|
||||
create_chat_file chat.json user "こんにちは" assistant "👋 hello 世界"
|
||||
|
||||
# Stage the rebase editor output (pick all)
|
||||
cat > .editor_input_0 << 'EDITEOF'
|
||||
# History Rebase Editor
|
||||
#
|
||||
# Commands:
|
||||
# pick - keep the message unchanged
|
||||
# edit - modify the message content and/or role
|
||||
# drop - remove the message from history
|
||||
#
|
||||
# Each line format: <command> <index> [<role>] <display_content>
|
||||
# - index: 0-based message index
|
||||
# - role: [user], [assistant], or [tool] (editable)
|
||||
# - display_content: first line of message (display only, not editable here)
|
||||
#
|
||||
# Lines starting with # are comments and will be ignored.
|
||||
# Empty lines are treated as drops.
|
||||
#
|
||||
-- >8 --
|
||||
pick 0 [user] こんにちは
|
||||
pick 1 [assistant] 👋 hello 世界
|
||||
EDITEOF
|
||||
|
||||
# Run drharness with -b flag
|
||||
set +e
|
||||
VISUAL="$MOCK_EDITOR" run_drharness -b -F chat.json
|
||||
EXIT_CODE=$?
|
||||
OUTPUT=$(get_output)
|
||||
set -e
|
||||
|
||||
if [ ${EXIT_CODE} -ne 0 ]; then
|
||||
echo "FAIL: $test_name - expected exit code 0, got $EXIT_CODE"
|
||||
echo "Output: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify history still has 2 messages
|
||||
local len=$(history_length chat.json)
|
||||
if [ "$len" != "2" ]; then
|
||||
echo "FAIL: $test_name - expected 2 messages, got $len"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify message content preserved unicode
|
||||
local msg0_content=$(dr_result chat.json 0)
|
||||
if [ "$msg0_content" != "こんにちは" ]; then
|
||||
echo "FAIL: $test_name - message 0 unicode not preserved, got: $msg0_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local msg1_content=$(dr_result chat.json 1)
|
||||
if [ "$msg1_content" != "👋 hello 世界" ]; then
|
||||
echo "FAIL: $test_name - message 1 unicode not preserved, got: $msg1_content"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Run all tests
|
||||
test_pick_all_messages
|
||||
test_no_edits_history_unchanged
|
||||
@@ -937,5 +1464,12 @@ test_invalid_index_error
|
||||
test_invalid_role_error
|
||||
test_multiple_edits
|
||||
test_edit_then_continue
|
||||
test_edit_remove_all_content
|
||||
test_multiple_consecutive_edits_same_message
|
||||
test_edit_special_characters
|
||||
test_very_long_content
|
||||
test_edit_assistant_with_tool_calls
|
||||
test_drop_all_messages
|
||||
test_unicode_characters
|
||||
|
||||
echo "All edit_history integration tests passed"
|
||||
|
||||
@@ -210,6 +210,68 @@ test_scissors_line() {
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 10: Special characters in content
|
||||
test_special_characters() {
|
||||
local test_name="special_characters"
|
||||
|
||||
local json='[{"role":"user","content":"hello \"quotes\" and $dollar"},{"role":"assistant","content":"backslash\\here"}]'
|
||||
|
||||
OUTPUT=$("${DRHARNESS}" -B "$json")
|
||||
|
||||
# Should handle quotes and special characters
|
||||
if ! echo "$OUTPUT" | grep -q "pick 0 \[user\]"; then
|
||||
echo "FAIL: $test_name - should handle special characters"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 11: Unicode characters in content
|
||||
test_unicode_characters() {
|
||||
local test_name="unicode_characters"
|
||||
|
||||
local json='[{"role":"user","content":"こんにちは"},{"role":"assistant","content":"👋 hello 世界"}]'
|
||||
|
||||
OUTPUT=$("${DRHARNESS}" -B "$json")
|
||||
|
||||
# Should preserve unicode characters
|
||||
if ! echo "$OUTPUT" | grep -q "pick 0 \[user\] こんにちは"; then
|
||||
echo "FAIL: $test_name - should preserve unicode"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$OUTPUT" | grep -q "pick 1 \[assistant\] 👋 hello 世界"; then
|
||||
echo "FAIL: $test_name - should preserve unicode emoji and CJK"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 12: Very long content (truncation test)
|
||||
test_very_long_content() {
|
||||
local test_name="very_long_content"
|
||||
|
||||
# Create a very long string (1000 characters)
|
||||
local long_content=$(printf 'x%.0s' {1..1000})
|
||||
local json="[{\"role\":\"user\",\"content\":\"$long_content\"}]"
|
||||
|
||||
OUTPUT=$("${DRHARNESS}" -B "$json")
|
||||
|
||||
# Should handle long content without crashing
|
||||
if ! echo "$OUTPUT" | grep -q "pick 0 \[user\]"; then
|
||||
echo "FAIL: $test_name - should handle long content"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Run all tests
|
||||
test_basic_messages
|
||||
test_multiline_content
|
||||
@@ -220,6 +282,9 @@ test_header_comments
|
||||
test_multiple_tool_calls
|
||||
test_message_indices
|
||||
test_scissors_line
|
||||
test_special_characters
|
||||
test_unicode_characters
|
||||
test_very_long_content
|
||||
|
||||
echo ""
|
||||
echo "All tests completed."
|
||||
|
||||
@@ -334,6 +334,52 @@ test_missing_role() {
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 15: Pick commands with whitespace variations
|
||||
test_whitespace_variations() {
|
||||
local test_name="whitespace_variations"
|
||||
|
||||
# Test with multiple spaces between fields
|
||||
local content="pick 0 [user] hello
|
||||
edit 1 [assistant] response
|
||||
drop 2 [tool] result"
|
||||
|
||||
OUTPUT=$("${DRHARNESS}" -P 3 "$content")
|
||||
|
||||
local count=$(rebase_line_count "$OUTPUT")
|
||||
if [ "$count" -ne 3 ]; then
|
||||
echo "FAIL: $test_name - expected 3 lines, got $count"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Test 16: Comments and empty lines mixed with commands
|
||||
test_comments_and_empty_lines_mixed() {
|
||||
local test_name="comments_and_empty_lines_mixed"
|
||||
|
||||
local content="# Header comment
|
||||
pick 0 [user] hello
|
||||
|
||||
# Middle comment
|
||||
edit 1 [assistant] response
|
||||
|
||||
drop 2 [tool] result
|
||||
# Footer comment"
|
||||
|
||||
OUTPUT=$("${DRHARNESS}" -P 3 "$content")
|
||||
|
||||
local count=$(rebase_line_count "$OUTPUT")
|
||||
if [ "$count" -ne 3 ]; then
|
||||
echo "FAIL: $test_name - expected 3 lines, got $count"
|
||||
echo "Got: $OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: $test_name"
|
||||
}
|
||||
|
||||
# Run all tests
|
||||
test_valid_rebase_all_commands
|
||||
test_valid_rebase_with_comments
|
||||
@@ -350,6 +396,8 @@ test_all_valid_roles
|
||||
test_invalid_command_digit
|
||||
test_invalid_index
|
||||
test_missing_role
|
||||
test_whitespace_variations
|
||||
test_comments_and_empty_lines_mixed
|
||||
|
||||
echo ""
|
||||
echo "All tests completed."
|
||||
|
||||
Reference in New Issue
Block a user