337 lines
7.7 KiB
Go
337 lines
7.7 KiB
Go
package notify
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestDesktopNotifier(t *testing.T) {
|
|
desktop := Desktop{}
|
|
|
|
t.Run("RecordingStarted", func(t *testing.T) {
|
|
// This test will actually try to call notify-send if available
|
|
// We can't easily mock exec.Command, so we just verify it doesn't panic
|
|
desktop.RecordingStarted()
|
|
})
|
|
|
|
t.Run("RecordingEnded", func(t *testing.T) {
|
|
desktop.RecordingEnded()
|
|
})
|
|
|
|
t.Run("Transcribing", func(t *testing.T) {
|
|
desktop.Transcribing()
|
|
})
|
|
|
|
t.Run("Aborted", func(t *testing.T) {
|
|
desktop.Aborted()
|
|
})
|
|
|
|
t.Run("Error", func(t *testing.T) {
|
|
desktop.Error("test error message")
|
|
})
|
|
|
|
t.Run("Notify", func(t *testing.T) {
|
|
desktop.Notify("Test Title", "Test Message")
|
|
})
|
|
}
|
|
|
|
func TestLogNotifier(t *testing.T) {
|
|
// Capture log output
|
|
var buf bytes.Buffer
|
|
log.SetOutput(&buf)
|
|
defer log.SetOutput(os.Stderr)
|
|
|
|
logNotifier := Log{}
|
|
|
|
t.Run("RecordingStarted", func(t *testing.T) {
|
|
buf.Reset()
|
|
logNotifier.RecordingStarted()
|
|
|
|
output := buf.String()
|
|
if output == "" {
|
|
t.Error("should log recording started message")
|
|
}
|
|
if !containsSubstring(output, "Hyprvoice") || !containsSubstring(output, "Recording Started") {
|
|
t.Errorf("log output should contain expected message, got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("RecordingEnded", func(t *testing.T) {
|
|
buf.Reset()
|
|
logNotifier.RecordingEnded()
|
|
|
|
output := buf.String()
|
|
if !containsSubstring(output, "Recording Ended") {
|
|
t.Errorf("log output should contain 'Recording Ended', got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("Transcribing", func(t *testing.T) {
|
|
buf.Reset()
|
|
logNotifier.Transcribing()
|
|
|
|
output := buf.String()
|
|
if !containsSubstring(output, "Transcribing") {
|
|
t.Errorf("log output should contain 'Transcribing', got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("Aborted", func(t *testing.T) {
|
|
buf.Reset()
|
|
logNotifier.Aborted()
|
|
|
|
output := buf.String()
|
|
if !containsSubstring(output, "Aborted") {
|
|
t.Errorf("log output should contain 'Aborted', got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("Error", func(t *testing.T) {
|
|
buf.Reset()
|
|
testMsg := "test error message"
|
|
logNotifier.Error(testMsg)
|
|
|
|
output := buf.String()
|
|
if !containsSubstring(output, "Hyprvoice Error") || !containsSubstring(output, testMsg) {
|
|
t.Errorf("log output should contain error message, got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("Notify", func(t *testing.T) {
|
|
buf.Reset()
|
|
title := "Test Title"
|
|
message := "Test Message"
|
|
logNotifier.Notify(title, message)
|
|
|
|
output := buf.String()
|
|
if !containsSubstring(output, title) || !containsSubstring(output, message) {
|
|
t.Errorf("log output should contain title and message, got: %s", output)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestNopNotifier(t *testing.T) {
|
|
nop := Nop{}
|
|
|
|
// All Nop methods should do nothing and not panic
|
|
t.Run("all methods should not panic", func(t *testing.T) {
|
|
nop.RecordingStarted()
|
|
nop.RecordingEnded()
|
|
nop.Transcribing()
|
|
nop.Aborted()
|
|
nop.Error("test message")
|
|
nop.Notify("title", "message")
|
|
})
|
|
}
|
|
|
|
func TestNotifierInterface(t *testing.T) {
|
|
// Verify all types implement the Notifier interface
|
|
var notifiers []Notifier = []Notifier{
|
|
Desktop{},
|
|
Log{},
|
|
Nop{},
|
|
}
|
|
|
|
for i, notifier := range notifiers {
|
|
t.Run("interface compliance", func(t *testing.T) {
|
|
// Test that all interface methods can be called
|
|
notifier.RecordingStarted()
|
|
notifier.RecordingEnded()
|
|
notifier.Transcribing()
|
|
notifier.Aborted()
|
|
notifier.Error("test")
|
|
notifier.Notify("title", "message")
|
|
})
|
|
|
|
// Verify the notifier is not nil
|
|
if notifier == nil {
|
|
t.Errorf("notifier %d should not be nil", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNotifierBehaviorConsistency(t *testing.T) {
|
|
// Test that different notifiers handle the same inputs consistently
|
|
testCases := []struct {
|
|
name string
|
|
title string
|
|
message string
|
|
}{
|
|
{"empty strings", "", ""},
|
|
{"normal strings", "Title", "Message"},
|
|
{"unicode strings", "📢 Alert", "🎙️ Recording"},
|
|
{"long strings", "Very Long Title That Might Cause Issues", "Very long message that contains a lot of text and might cause formatting issues or truncation in some notification systems"},
|
|
{"special characters", "Title with \n newlines", "Message with \"quotes\" and 'apostrophes'"},
|
|
}
|
|
|
|
notifiers := map[string]Notifier{
|
|
"Desktop": Desktop{},
|
|
"Log": Log{},
|
|
"Nop": Nop{},
|
|
}
|
|
|
|
for notifierName, notifier := range notifiers {
|
|
for _, tc := range testCases {
|
|
t.Run(notifierName+"_"+tc.name, func(t *testing.T) {
|
|
// These should not panic regardless of input
|
|
notifier.Notify(tc.title, tc.message)
|
|
notifier.Error(tc.message)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLogNotifierOutput(t *testing.T) {
|
|
// More detailed testing of log output format
|
|
var buf bytes.Buffer
|
|
log.SetOutput(&buf)
|
|
defer log.SetOutput(os.Stderr)
|
|
|
|
logNotifier := Log{}
|
|
|
|
t.Run("log format consistency", func(t *testing.T) {
|
|
testCases := []struct {
|
|
method func()
|
|
expected []string
|
|
}{
|
|
{
|
|
method: logNotifier.RecordingStarted,
|
|
expected: []string{"Hyprvoice", "Recording Started"},
|
|
},
|
|
{
|
|
method: logNotifier.RecordingEnded,
|
|
expected: []string{"Hyprvoice", "Recording Ended"},
|
|
},
|
|
{
|
|
method: logNotifier.Transcribing,
|
|
expected: []string{"Hyprvoice", "Transcribing"},
|
|
},
|
|
{
|
|
method: logNotifier.Aborted,
|
|
expected: []string{"Hyprvoice", "Aborted"},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
buf.Reset()
|
|
tc.method()
|
|
output := buf.String()
|
|
|
|
for _, expected := range tc.expected {
|
|
if !containsSubstring(output, expected) {
|
|
t.Errorf("log output should contain %q, got: %s", expected, output)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("error method with different messages", func(t *testing.T) {
|
|
errorMessages := []string{
|
|
"simple error",
|
|
"error with numbers 123",
|
|
"error with symbols !@#$%",
|
|
"",
|
|
}
|
|
|
|
for _, msg := range errorMessages {
|
|
buf.Reset()
|
|
logNotifier.Error(msg)
|
|
output := buf.String()
|
|
|
|
if !containsSubstring(output, "Hyprvoice Error") {
|
|
t.Errorf("error log should contain 'Hyprvoice Error', got: %s", output)
|
|
}
|
|
|
|
if msg != "" && !containsSubstring(output, msg) {
|
|
t.Errorf("error log should contain message %q, got: %s", msg, output)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestNotifierMethods(t *testing.T) {
|
|
// Test that all required methods exist and can be called
|
|
var n Notifier
|
|
|
|
// Test with each implementation
|
|
implementations := []Notifier{
|
|
Desktop{},
|
|
Log{},
|
|
Nop{},
|
|
}
|
|
|
|
for _, impl := range implementations {
|
|
n = impl
|
|
|
|
// Verify all methods exist by calling them
|
|
n.RecordingStarted()
|
|
n.RecordingEnded()
|
|
n.Aborted()
|
|
n.Transcribing()
|
|
n.Error("test")
|
|
n.Notify("test", "test")
|
|
}
|
|
}
|
|
|
|
func TestNotifierEdgeCases(t *testing.T) {
|
|
notifiers := []Notifier{Desktop{}, Log{}, Nop{}}
|
|
|
|
t.Run("nil message handling", func(t *testing.T) {
|
|
for _, notifier := range notifiers {
|
|
// These should not panic even with empty strings
|
|
notifier.Error("")
|
|
notifier.Notify("", "")
|
|
notifier.Notify("title", "")
|
|
notifier.Notify("", "message")
|
|
}
|
|
})
|
|
|
|
t.Run("concurrent access", func(t *testing.T) {
|
|
for _, notifier := range notifiers {
|
|
done := make(chan bool, 10)
|
|
|
|
// Call methods concurrently
|
|
for i := 0; i < 10; i++ {
|
|
go func(id int) {
|
|
notifier.RecordingStarted()
|
|
notifier.RecordingEnded()
|
|
notifier.Transcribing()
|
|
notifier.Aborted()
|
|
notifier.Error("concurrent test")
|
|
notifier.Notify("title", "message")
|
|
done <- true
|
|
}(i)
|
|
}
|
|
|
|
// Wait for all goroutines
|
|
for i := 0; i < 10; i++ {
|
|
<-done
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Helper function to check if a string contains a substring
|
|
func containsSubstring(s, substr string) bool {
|
|
return len(s) >= len(substr) && findSubstring(s, substr) >= 0
|
|
}
|
|
|
|
// Simple substring search
|
|
func findSubstring(s, substr string) int {
|
|
if len(substr) == 0 {
|
|
return 0
|
|
}
|
|
if len(substr) > len(s) {
|
|
return -1
|
|
}
|
|
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|