package main import ( "context" "io" "log" "os" "path/filepath" "testing" "time" "github.com/stretchr/testify/require" "go.mau.fi/whatsmeow/types/events" ) func TestWhatsAppStatusFollowsTheConnection(t *testing.T) { dir := t.TempDir() whatsappTestSession(t, dir, true) clock := newTestClock() fake := &WhatsAppFake{ connected: make(chan struct{}), } whatsapp, err := openWhatsApp(t.Context(), dir, clock.Now, log.New(io.Discard, "", 0), fake.newClient) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, whatsapp.Close()) }) ctx, cancel := context.WithCancel(t.Context()) done := make(chan struct{}) go func() { defer close(done) whatsapp.Run(ctx) }() t.Cleanup(func() { cancel() <-done }) <-fake.connected require.Equal(t, "WhatsApp is linked and not connected yet.", whatsapp.Status()) require.True(t, fake.Emit(&events.Connected{})) require.Equal(t, "WhatsApp is linked and connected since 2026-01-01 12:00.", whatsapp.Status()) clock.now = clock.now.Add(20 * time.Minute) require.True(t, fake.Emit(&events.Disconnected{})) clock.now = clock.now.Add(time.Minute) require.True(t, fake.Emit(&events.Disconnected{})) require.Equal(t, "WhatsApp is linked and disconnected since 2026-01-01 12:20. The last connection started at 2026-01-01 12:00.", whatsapp.Status()) } func TestWhatsAppStatusOfAFirstConnectionThatFailed(t *testing.T) { dir := t.TempDir() whatsappTestSession(t, dir, true) whatsapp, fake := whatsappStartTest(t, dir) ctx, cancel := context.WithCancel(t.Context()) done := make(chan struct{}) go func() { defer close(done) whatsapp.Run(ctx) }() t.Cleanup(func() { cancel() <-done }) <-fake.connected require.True(t, fake.Emit(&events.Disconnected{})) require.Equal(t, "WhatsApp is linked and disconnected since 2026-01-01 12:00.", whatsapp.Status()) } func TestWhatsAppIsNotLinkedWithoutALinkedDevice(t *testing.T) { testCases := []struct { name string session func(t *testing.T, dir string) }{ { name: "no session file", session: func(t *testing.T, dir string) { }, }, { name: "a session of a pairing that did not end", session: func(t *testing.T, dir string) { whatsappTestSession(t, dir, false) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { dir := t.TempDir() tc.session(t, dir) whatsapp, _ := whatsappStartTest(t, dir) require.Equal(t, "WhatsApp is not linked.", whatsapp.Status()) }) } } func TestWhatsAppRefusesASessionThatOthersCanRead(t *testing.T) { dir := t.TempDir() whatsappTestSession(t, dir, true) require.NoError(t, os.Chmod(filepath.Join(dir, whatsappDirName, whatsappSessionFileName), 0o644)) _, err := openWhatsApp(t.Context(), dir, time.Now, log.New(io.Discard, "", 0), whatsappNewClient) require.EqualError(t, err, "whatsapp/session.db holds the WhatsApp session, so its mode must be 0600") } func TestWhatsAppCommandsAnswerOnlyTheClientThatAsked(t *testing.T) { server := newModelFake(t) telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) socket := daemonStartTestWithBot(t, server, bot) asking := terminalStartTestClient(t, socket) other := terminalStartTestClient(t, socket) asking.WaitFor(t, "[connected to OneChat]") other.WaitFor(t, "[connected to OneChat]") asking.Type("/whatsapp status") asking.WaitFor(t, "WhatsApp is not linked.") asking.Type(" /whatsapp unknown ") asking.WaitFor(t, whatsappUsage) telegram.Add(TelegramUpdate{ UpdateID: 1, Message: telegramOwnerMessage("/whatsapp status"), }) telegramWaitForSent(t, telegram, "WhatsApp is not linked.") require.Equal(t, []string{"WhatsApp is not linked."}, telegram.Sent()) require.Equal(t, "[connected to OneChat]\n", other.Output()) require.Zero(t, server.Calls()) } func TestWhatsAppCommandArgs(t *testing.T) { testCases := []struct { name string line string args string found bool }{ { name: "a command with its arguments", line: " /whatsapp pair +1 555 ", args: "pair +1 555", found: true, }, { name: "the command alone", line: "/whatsapp", args: "", found: true, }, { name: "a word that starts with the command", line: "/whatsappstatus", args: "", found: false, }, { name: "a message that names the command", line: "what does /whatsapp status do?", args: "", found: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { args, found := whatsappCommandArgs(tc.line) require.Equal(t, tc.args, args) require.Equal(t, tc.found, found) }) } }