Files
2026-07-13 12:30:20 +08:00

934 lines
25 KiB
Go

package sync
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestMergePrefixCases(t *testing.T) {
r := require.New(t)
original := "line 1\nline 2"
modified := "line 1\nline 2\nline 3\nline 4"
r.Equal(modified, Merge(original, modified))
r.Equal(modified, Merge(modified, original))
}
func TestMergeCommonPrefixDifferentSuffixes(t *testing.T) {
r := require.New(t)
// Both have common prefix but different additional lines
original := "line 1\nline 2\nline 3\nline original 4"
modified := "line 1\nline 2\nline 3\nline modified 4"
merged := Merge(original, modified)
r.Equal("line 1\nline 2\nline 3\nline original 4\nline modified 4", merged)
}
func TestMergeDifferentPrefixCommonSuffix(t *testing.T) {
r := require.New(t)
// Both have different prefixes but common suffix
original := "line original 1\nline original 2\nline 3"
modified := "new\nline original 1\nline original 2\nline 3"
merged := Merge(original, modified)
r.Equal("new\nline original 1\nline original 2\nline 3", merged, "Should merge lines before common suffix")
}
func TestMergeDivergentBody(t *testing.T) {
r := require.New(t)
// Divergent content with common prefix and suffix
original := "header\nheader\noriginal A\noriginal B\nfooter\nfooter"
modified := "header\nheader\nmodified X\nmodified Y\nfooter\nfooter"
merged := Merge(original, modified)
r.Equal("header\nheader\noriginal A\noriginal B\nmodified X\nmodified Y\nfooter\nfooter", merged)
}
func TestMergeSameHeader(t *testing.T) {
r := require.New(t)
result := Merge("#### 23 May, Saturday", "#### 23 May, Saturday")
r.Equal("#### 23 May, Saturday", result)
}
func TestMergeDivergentContent(t *testing.T) {
r := require.New(t)
// Complete divergence with small common prefix
original := "header\noriginal A\noriginal B"
modified := "header\nmodified X\nmodified Y"
merged := Merge(original, modified)
r.Equal("header\noriginal A\noriginal B\nmodified X\nmodified Y", merged)
}
func TestMergeEmptyStrings(t *testing.T) {
r := require.New(t)
r.Equal("", Merge("", ""), "Empty strings should merge to empty string")
r.Equal("content", Merge("", "content"), "Empty original should return modified")
r.Equal("content", Merge("content", ""), "Empty modified should return original")
}
func TestMergeTrailingNewlines(t *testing.T) {
r := require.New(t)
original := "line 1\nline 2\n"
modified := "line 1\nline 2\nline 3\n"
r.Equal(modified, Merge(original, modified), "Should handle trailing newlines correctly")
}
func TestMergeDivergentChars(t *testing.T) {
r := require.New(t)
original := "abc"
modified := "adc"
merged := Merge(original, modified)
r.Equal("abc\nadc", merged)
}
func TestJournal(t *testing.T) {
r := require.New(t)
server := "1 April\nfelt good\nate good\n2 April\nslept not so good"
client := "1 April\nfelt good\n2 April\nslept not so good\nwent for hiking"
merged := Merge(server, client)
r.Equal("1 April\nfelt good\nate good\n2 April\nslept not so good\nwent for hiking", merged)
}
func TestMergeHeaders(t *testing.T) {
r := require.New(t)
headers := []string{"#### 23 May, Friday 🤸‍♂️🍽💪💧", "#### 23 May, Friday 🤸‍♂️🍽💪", "#### 23 May, Friday 🤸‍♂️"}
merged := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪💧"}, merged)
}
func TestMergeHeadersReversed(t *testing.T) {
r := require.New(t)
headers := []string{"#### 23 May, Friday 🤸‍♂️", "#### 23 May, Friday 🤸‍♂️🍽💪", "#### 23 May, Friday 🤸‍♂️🍽💪💧"}
merged := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪💧"}, merged)
}
func TestMergeHeadersWithDifferentEmojis(t *testing.T) {
r := require.New(t)
headers := []string{"#### 23 May, Friday 🤸‍♂️‍🍽💪💧", "#### 23 May, Friday 🤸‍♂️🍽💪📵🚶‍♂️"}
merged := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️‍🍽💪💧📵🚶‍♂️"}, merged)
}
func TestMergeHeadersNoEmoji(t *testing.T) {
r := require.New(t)
headers := []string{"#### 23 May, Friday", "#### 23 May, Friday 💪"}
merged := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 💪"}, merged)
headers = []string{"#### 23 May, Saturday", "#### 23 May, Saturday"}
merged = mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Saturday"}, merged)
}
// AI-gen tests
func TestMergeCompletelyDifferent(t *testing.T) {
r := require.New(t)
original := "apple\nbanana\ncherry"
modified := "dog\nelephant\nfox"
merged := Merge(original, modified)
r.Equal("apple\nbanana\ncherry\ndog\nelephant\nfox", merged)
}
func TestMergeRepeatedLines(t *testing.T) {
r := require.New(t)
original := "repeat\nrepeat\nunique1"
modified := "repeat\nrepeat\nunique2"
merged := Merge(original, modified)
r.Equal("repeat\nrepeat\nunique1\nunique2", merged)
}
func TestMergeWithBlankLines(t *testing.T) {
r := require.New(t)
original := "line1\n\nline3"
modified := "line1\nline2\n\nline3"
merged := Merge(original, modified)
r.Equal("line1\nline2\n\nline3", merged)
}
func TestMergeMultipleBlankLines(t *testing.T) {
r := require.New(t)
original := "start\n\n\nend"
modified := "start\nmiddle\n\n\nend"
merged := Merge(original, modified)
r.Equal("start\nmiddle\n\n\nend", merged)
}
func TestMergeOnlyBlankLines(t *testing.T) {
r := require.New(t)
original := "\n\n"
modified := "\n\n\n"
merged := Merge(original, modified)
r.Equal("\n\n\n", merged)
}
func TestMergeSingleLineStrings(t *testing.T) {
r := require.New(t)
r.Equal("hello", Merge("hello", "hello"))
r.Equal("hello\nworld", Merge("hello", "world"))
r.Equal("world\nhello", Merge("world", "hello"))
}
func TestMergeVeryLongCommonPrefix(t *testing.T) {
r := require.New(t)
commonLines := make([]string, 100)
for i := 0; i < 100; i++ {
commonLines[i] = fmt.Sprintf("common line %d", i)
}
commonPrefix := strings.Join(commonLines, "\n")
original := commonPrefix + "\noriginal ending"
modified := commonPrefix + "\nmodified ending"
merged := Merge(original, modified)
expected := commonPrefix + "\noriginal ending\nmodified ending"
r.Equal(expected, merged)
}
func TestMergeVeryLongCommonSuffix(t *testing.T) {
r := require.New(t)
commonLines := make([]string, 100)
for i := 0; i < 100; i++ {
commonLines[i] = fmt.Sprintf("common line %d", i)
}
commonSuffix := strings.Join(commonLines, "\n")
original := "original start\n" + commonSuffix
modified := "modified start\n" + commonSuffix
merged := Merge(original, modified)
expected := "original start\nmodified start\n" + commonSuffix
r.Equal(expected, merged)
}
func TestMergeNestedCommonSubsequences(t *testing.T) {
r := require.New(t)
// Complex case with multiple common subsequences
original := "A\nB\nC\nX\nD\nE\nY\nF"
modified := "A\nB\nZ\nC\nD\nE\nW\nF"
merged := Merge(original, modified)
// Should preserve the LCS while adding unique content
r.Contains(merged, "A")
r.Contains(merged, "B")
r.Contains(merged, "C")
r.Contains(merged, "D")
r.Contains(merged, "E")
r.Contains(merged, "F")
r.Contains(merged, "X")
r.Contains(merged, "Y")
r.Contains(merged, "Z")
r.Contains(merged, "W")
}
func TestMergeWithSpecialCharacters(t *testing.T) {
r := require.New(t)
original := "line with\ttabs\nline with spaces"
modified := "line with\ttabs\nline with multiple spaces"
merged := Merge(original, modified)
r.Equal("line with\ttabs\nline with spaces\nline with multiple spaces", merged)
}
func TestMergeUnicodeContent(t *testing.T) {
r := require.New(t)
original := "Hello 世界\n🌍 Earth"
modified := "Hello 世界\n🌍 Earth\n🚀 Space"
merged := Merge(original, modified)
r.Equal("Hello 世界\n🌍 Earth\n🚀 Space", merged)
}
func TestMergeVeryLongLines(t *testing.T) {
r := require.New(t)
longLine := strings.Repeat("a", 10000)
original := longLine + "\nshort"
modified := longLine + "\ndifferent"
merged := Merge(original, modified)
r.Equal(longLine+"\nshort\ndifferent", merged)
}
func TestMergeIdenticalContent(t *testing.T) {
r := require.New(t)
content := "line1\nline2\nline3\nline4\nline5"
r.Equal(content, Merge(content, content))
}
func TestMergeOneIsSubsetOfOther(t *testing.T) {
r := require.New(t)
subset := "line2\nline4"
superset := "line1\nline2\nline3\nline4\nline5"
// Test both directions
r.Equal(superset, Merge(subset, superset))
r.Equal(superset, Merge(superset, subset))
}
func TestMergeAlternatingPattern(t *testing.T) {
r := require.New(t)
// Alternating common and unique lines
original := "common1\nunique1\ncommon2\nunique2\ncommon3"
modified := "common1\ndifferent1\ncommon2\ndifferent2\ncommon3"
merged := Merge(original, modified)
r.Contains(merged, "common1")
r.Contains(merged, "common2")
r.Contains(merged, "common3")
r.Contains(merged, "unique1")
r.Contains(merged, "unique2")
r.Contains(merged, "different1")
r.Contains(merged, "different2")
}
func TestMergeRealWorldScenario(t *testing.T) {
r := require.New(t)
// Simulating a config file merge
original := `# Configuration file
version: 1.0
database:
host: localhost
port: 5432
logging:
level: info`
modified := `# Configuration file
version: 1.0
database:
host: localhost
port: 5432
timeout: 30
logging:
level: debug
file: app.log`
merged := Merge(original, modified)
// Should contain all unique lines from both
r.Contains(merged, "# Configuration file")
r.Contains(merged, "version: 1.0")
r.Contains(merged, "database:")
r.Contains(merged, " host: localhost")
r.Contains(merged, " port: 5432")
r.Contains(merged, " timeout: 30")
r.Contains(merged, "logging:")
r.Contains(merged, " level: info")
r.Contains(merged, " level: debug")
r.Contains(merged, " file: app.log")
}
func TestMergeJournalWithTasks(t *testing.T) {
r := require.New(t)
// More complex journal scenario
original := `#### 24 May, Sunday
Morning routine
- Coffee ☕
- Exercise 💪
Evening reflection
- Good day overall`
modified := `#### 24 May, Sunday
Morning routine
- Coffee ☕
- Read news 📰
- Exercise 💪
Afternoon work
- Team meeting
Evening reflection
- Good day overall
- Grateful for sunshine`
merged := Merge(original, modified)
// Should preserve the structure while adding new content
r.Contains(merged, "#### 24 May, Sunday")
r.Contains(merged, "Morning routine")
r.Contains(merged, "- Coffee ☕")
r.Contains(merged, "- Exercise 💪")
r.Contains(merged, "- Read news 📰")
r.Contains(merged, "Afternoon work")
r.Contains(merged, "- Team meeting")
r.Contains(merged, "Evening reflection")
r.Contains(merged, "- Good day overall")
r.Contains(merged, "- Grateful for sunshine")
}
func TestMergeEmojisInJournalHeaders_SingleHeader(t *testing.T) {
r := require.New(t)
// Single header with emojis
headers := []string{"#### 23 May, Friday 🤸‍♂️🍽💪"}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪"}, result)
// Single header without emojis
headers = []string{"#### 23 May, Friday"}
result = mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday"}, result)
}
func TestMergeEmojisInJournalHeaders_MultipleHeadersSameDate(t *testing.T) {
r := require.New(t)
// Multiple headers with same date, different emojis
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday 🍽💪",
"#### 23 May, Friday 💧",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪💧"}, result)
}
func TestMergeEmojisInJournalHeaders_OverlappingEmojis(t *testing.T) {
r := require.New(t)
// Headers with overlapping emojis - should deduplicate
headers := []string{
"#### 23 May, Friday 🤸‍♂️🍽💪",
"#### 23 May, Friday 🍽💪💧",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪💧"}, result)
}
func TestMergeEmojisInJournalHeaders_DifferentDates(t *testing.T) {
r := require.New(t)
// Headers with different dates - should not merge
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 24 May, Saturday 🍽💪",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{
"#### 23 May, Friday 🤸‍♂️",
"#### 24 May, Saturday 🍽💪",
}, result)
}
func TestMergeEmojisInJournalHeaders_PartialDateMatch(t *testing.T) {
r := require.New(t)
// Headers where one starts with part of another's date - should not merge
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday evening 🍽💪",
}
result := mergeEmojisInJournalHeaders(headers)
// Should not merge because "#### 23 May, Friday evening" doesn't start with "#### 23 May, Friday"
r.Equal([]string{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday evening 🍽💪",
}, result)
}
func TestMergeTwoNonHeaders(t *testing.T) {
r := require.New(t)
// Headers where one starts with part of another's date - should not merge
headers := []string{
"#### 🤸‍♂️",
"#### 🍽💪",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{
"#### 🤸‍♂️",
"#### 🍽💪",
}, result)
}
func TestMergeEmojisInJournalHeaders_NoEmojis(t *testing.T) {
r := require.New(t)
// Multiple headers with same date but no emojis
headers := []string{
"#### 23 May, Friday",
"#### 23 May, Friday",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday"}, result)
}
func TestMergeEmojisInJournalHeaders_MixedEmojiAndNoEmoji(t *testing.T) {
r := require.New(t)
// Mix of headers with and without emojis
headers := []string{
"#### 23 May, Friday",
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday 🍽💪",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🤸‍♂️🍽💪"}, result)
}
func TestMergeEmojisInJournalHeaders_NonHeaderLines(t *testing.T) {
r := require.New(t)
// Mix of headers and non-headers
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"This is not a header",
"Neither is this",
"#### 24 May, Saturday 🍽💪",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{
"#### 23 May, Friday 🤸‍♂️",
"This is not a header",
"Neither is this",
"#### 24 May, Saturday 🍽💪",
}, result)
}
func TestMergeEmojisInJournalHeaders_ConsecutiveGroupsWithNonHeaders(t *testing.T) {
r := require.New(t)
// Multiple groups separated by non-headers
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday 🍽",
"Some content here",
"#### 24 May, Saturday 💪",
"#### 24 May, Saturday 💧",
"More content",
"#### 25 May, Sunday 🚶‍♂️",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{
"#### 23 May, Friday 🤸‍♂️🍽",
"Some content here",
"#### 24 May, Saturday 💪💧",
"More content",
"#### 25 May, Sunday 🚶‍♂️",
}, result)
}
func TestMergeEmojisInJournalHeaders_ComplexEmojis(t *testing.T) {
r := require.New(t)
// Test with complex emojis (multi-byte, skin tones, etc.)
headers := []string{
"#### 23 May, Friday 👨‍💻",
"#### 23 May, Friday 🏃‍♂️",
"#### 23 May, Friday 👍🏽",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 👨‍💻🏃‍♂️👍🏽"}, result)
}
func TestMergeEmojisInJournalHeaders_EmojiOrder(t *testing.T) {
r := require.New(t)
// Test that emoji order is preserved
headers := []string{
"#### 23 May, Friday 🥇",
"#### 23 May, Friday 🥈",
"#### 23 May, Friday 🥉",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday 🥇🥈🥉"}, result)
}
func TestMergeEmojisInJournalHeaders_EmptyInput(t *testing.T) {
r := require.New(t)
result := mergeEmojisInJournalHeaders([]string{})
r.Empty(result)
result = mergeEmojisInJournalHeaders(nil)
r.Empty(result)
}
func TestMergeEmojisInJournalHeaders_BugFix_NonMergeable(t *testing.T) {
r := require.New(t)
// This test specifically targets the bug you found
// When headers can't be merged, foundEmojis is accumulated but not used
headers := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 24 May, Saturday 🍽💪", // Different date
}
result := mergeEmojisInJournalHeaders(headers)
// Should return original headers unchanged, not merged
r.Equal([]string{
"#### 23 May, Friday 🤸‍♂️",
"#### 24 May, Saturday 🍽💪",
}, result)
// The bug would have been that foundEmojis was being accumulated
// even when the headers couldn't be merged due to different dates
}
func TestMergeEmojisInJournalHeaders_SpecialCharacters(t *testing.T) {
r := require.New(t)
// Test with punctuation and special characters
headers := []string{
"#### 23 May, Friday! 🎉",
"#### 23 May, Friday! 🎊",
}
result := mergeEmojisInJournalHeaders(headers)
r.Equal([]string{"#### 23 May, Friday! 🎉🎊"}, result)
}
func TestMergeEmojisInJournalHeaders_RealWorldScenario(t *testing.T) {
r := require.New(t)
// Realistic journal headers as they might appear
headers := []string{
"#### 28 May, Wednesday 🌅", // morning entry
"#### 28 May, Wednesday 💼", // work entry
"#### 28 May, Wednesday 🍽️", // meal entry
"#### 28 May, Wednesday 🌙", // evening entry
"Some journal content here",
"#### 29 May, Thursday ☀️",
"#### 29 May, Thursday 🏃‍♂️💪",
}
result := mergeEmojisInJournalHeaders(headers)
expected := []string{
"#### 28 May, Wednesday 🌅💼🍽️🌙",
"Some journal content here",
"#### 29 May, Thursday ☀️🏃‍♂️💪",
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_SingleHeader(t *testing.T) {
r := require.New(t)
lines := []string{"#### 23 May, Friday"}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{"#### 23 May, Friday"}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_MultipleConsecutiveHeaders(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 May, Friday",
"#### 23 May, Saturday",
"#### 24 May, Sunday",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{
"#### 23 May, Friday",
"#### 23 May, Saturday",
"#### 24 May, Sunday",
}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_HeadersWithEmojis(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday 🍽💪",
"#### 24 May, Saturday 💧",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{
"#### 23 May, Friday 🤸‍♂️",
"#### 23 May, Friday 🍽💪",
"#### 24 May, Saturday 💧",
}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_NonHeaders(t *testing.T) {
r := require.New(t)
lines := []string{
"This is not a header",
"Neither is this",
"Just regular text",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{"This is not a header"},
{"Neither is this"},
{"Just regular text"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_MixedHeadersAndNonHeaders(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 May, Friday",
"#### 23 May, Saturday",
"Some journal content",
"More content",
"#### 24 May, Sunday",
"Final content",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{"#### 23 May, Friday", "#### 23 May, Saturday"},
{"Some journal content"},
{"More content"},
{"#### 24 May, Sunday"},
{"Final content"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_HeadersWithExtraSpaces(t *testing.T) {
r := require.New(t)
// Headers with extra spaces - should still match
lines := []string{
"#### 23 May, Friday ",
"#### 23 May, Saturday", // Extra space after ####
"#### 24 May, Sunday",
}
result := groupConsecutiveHeaders(lines)
// Only the properly formatted ones should be grouped as headers
expected := [][]string{
{"#### 23 May, Friday "},
{"#### 23 May, Saturday"}, // This won't match the regex
{"#### 24 May, Sunday"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_InvalidHeaderFormats(t *testing.T) {
r := require.New(t)
lines := []string{
"### 23 May, Friday", // Wrong number of #
"##### 23 May, Friday", // Too many #
"#### May 23, Friday", // Wrong date format
"#### 23 May Friday", // Missing comma
"#### 23 May,", // Missing day
"#### 23, Friday", // Missing month
"#### twenty May, Friday", // Non-numeric day
}
result := groupConsecutiveHeaders(lines)
// None should match, so each should be in its own group
expected := [][]string{
{"### 23 May, Friday"},
{"##### 23 May, Friday"},
{"#### May 23, Friday"},
{"#### 23 May Friday"},
{"#### 23 May,"},
{"#### 23, Friday"},
{"#### twenty May, Friday"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_ValidHeaderVariations(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 1 Jan, Monday",
"#### 10 February, Tuesday",
"#### 31 December, Wednesday",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{
"#### 1 Jan, Monday",
"#### 10 February, Tuesday",
"#### 31 December, Wednesday",
}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_MultipleGroups(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 May, Friday",
"#### 23 May, Saturday",
"Some content between groups",
"#### 24 May, Sunday",
"#### 24 May, Monday",
"More content",
"#### 25 May, Tuesday",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{"#### 23 May, Friday", "#### 23 May, Saturday"},
{"Some content between groups"},
{"#### 24 May, Sunday", "#### 24 May, Monday"},
{"More content"},
{"#### 25 May, Tuesday"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_SingleNonHeader(t *testing.T) {
r := require.New(t)
lines := []string{"Just some text"}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{"Just some text"}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_HeadersAtStartAndEnd(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 May, Friday",
"#### 23 May, Saturday",
"Middle content",
"#### 24 May, Sunday",
"#### 24 May, Monday",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{"#### 23 May, Friday", "#### 23 May, Saturday"},
{"Middle content"},
{"#### 24 May, Sunday", "#### 24 May, Monday"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_HeadersWithDifferentContent(t *testing.T) {
r := require.New(t)
// Headers with additional content after the date/day
lines := []string{
"#### 23 May, Friday - Good day",
"#### 23 May, Saturday 🌞 Sunny",
"#### 24 May, Sunday (rainy)",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{{
"#### 23 May, Friday - Good day",
"#### 23 May, Saturday 🌞 Sunny",
"#### 24 May, Sunday (rainy)",
}}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_EdgeCaseWhitespace(t *testing.T) {
r := require.New(t)
lines := []string{
"", // Empty line
"#### 23 May, Friday",
" ", // Line with just spaces
"#### 24 May, Saturday",
"",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{""},
{"#### 23 May, Friday"},
{" "},
{"#### 24 May, Saturday"},
{""},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_CaseSensitivity(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 23 may, friday", // lowercase
"#### 23 MAY, FRIDAY", // uppercase
"#### 23 May, Friday", // proper case
}
result := groupConsecutiveHeaders(lines)
// Only the properly cased one should match
expected := [][]string{
{"#### 23 may, friday", "#### 23 MAY, FRIDAY", "#### 23 May, Friday"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_RealWorldJournalExample(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 28 May, Wednesday",
"#### 28 May, Wednesday", // Duplicate header
"Morning routine:",
"- Coffee ☕",
"- Exercise 💪",
"",
"#### 29 May, Thursday",
"#### 29 May, Thursday",
"Work day:",
"- Team meeting",
"- Code review",
"",
"#### 30 May, Friday",
"TGIF! 🎉",
}
result := groupConsecutiveHeaders(lines)
expected := [][]string{
{"#### 28 May, Wednesday", "#### 28 May, Wednesday"},
{"Morning routine:"},
{"- Coffee ☕"},
{"- Exercise 💪"},
{""},
{"#### 29 May, Thursday", "#### 29 May, Thursday"},
{"Work day:"},
{"- Team meeting"},
{"- Code review"},
{""},
{"#### 30 May, Friday"},
{"TGIF! 🎉"},
}
r.Equal(expected, result)
}
func TestGroupConsecutiveHeaders_RegexEdgeCases(t *testing.T) {
r := require.New(t)
lines := []string{
"#### 0 May, Friday", // Zero day - should match \d+
"#### 99 December, Sunday", // Large day number
"#### 1 A, Monday", // Single letter month - should match \w+
"#### 1 Ab, Tuesday", // Two letter month
"#### 1 January, W", // Single letter day - should match \w+
"#### 1 January, Wednesday", // Full day name
}
result := groupConsecutiveHeaders(lines)
// All should match the regex pattern
expected := [][]string{{
"#### 0 May, Friday",
"#### 99 December, Sunday",
"#### 1 A, Monday",
"#### 1 Ab, Tuesday",
"#### 1 January, W",
"#### 1 January, Wednesday",
}}
r.Equal(expected, result)
}