import { describe, expect, mock, test } from "bun:test" import { LocationKey, LocationSource, type Location } from "./location-source.ts" function createLocation(overrides: Partial = {}): Location { return { lat: 37.7749, lng: -122.4194, accuracy: 10, timestamp: new Date(), ...overrides, } } describe("LocationSource", () => { describe("FeedSource interface", () => { test("has correct id", () => { const source = new LocationSource() expect(source.id).toBe("location") }) test("fetchItems always returns empty array", async () => { const source = new LocationSource() source.pushLocation(createLocation()) const items = await source.fetchItems() expect(items).toEqual([]) }) test("fetchContext returns empty when no location", async () => { const source = new LocationSource() const context = await source.fetchContext() expect(context).toEqual({}) }) test("fetchContext returns location when available", async () => { const source = new LocationSource() const location = createLocation() source.pushLocation(location) const context = await source.fetchContext() expect(context).toEqual({ [LocationKey]: location }) }) }) describe("pushLocation", () => { test("updates lastLocation", () => { const source = new LocationSource() expect(source.lastLocation).toBeNull() const location = createLocation() source.pushLocation(location) expect(source.lastLocation).toEqual(location) }) test("notifies listeners", () => { const source = new LocationSource() const listener = mock() source.onContextUpdate(listener) const location = createLocation() source.pushLocation(location) expect(listener).toHaveBeenCalledTimes(1) expect(listener).toHaveBeenCalledWith({ [LocationKey]: location }) }) }) describe("history", () => { test("default historySize is 1", () => { const source = new LocationSource() source.pushLocation(createLocation({ lat: 1 })) source.pushLocation(createLocation({ lat: 2 })) expect(source.locationHistory).toHaveLength(1) expect(source.lastLocation?.lat).toBe(2) }) test("respects configured historySize", () => { const source = new LocationSource({ historySize: 3 }) const loc1 = createLocation({ lat: 1 }) const loc2 = createLocation({ lat: 2 }) const loc3 = createLocation({ lat: 3 }) source.pushLocation(loc1) source.pushLocation(loc2) source.pushLocation(loc3) expect(source.locationHistory).toEqual([loc1, loc2, loc3]) }) test("evicts oldest when exceeding historySize", () => { const source = new LocationSource({ historySize: 2 }) const loc1 = createLocation({ lat: 1 }) const loc2 = createLocation({ lat: 2 }) const loc3 = createLocation({ lat: 3 }) source.pushLocation(loc1) source.pushLocation(loc2) source.pushLocation(loc3) expect(source.locationHistory).toEqual([loc2, loc3]) }) test("locationHistory is readonly", () => { const source = new LocationSource({ historySize: 3 }) source.pushLocation(createLocation()) const history = source.locationHistory expect(Array.isArray(history)).toBe(true) }) }) describe("onContextUpdate", () => { test("returns cleanup function", () => { const source = new LocationSource() const listener = mock() const cleanup = source.onContextUpdate(listener) source.pushLocation(createLocation({ lat: 1 })) expect(listener).toHaveBeenCalledTimes(1) cleanup() source.pushLocation(createLocation({ lat: 2 })) expect(listener).toHaveBeenCalledTimes(1) }) test("supports multiple listeners", () => { const source = new LocationSource() const listener1 = mock() const listener2 = mock() source.onContextUpdate(listener1) source.onContextUpdate(listener2) source.pushLocation(createLocation()) expect(listener1).toHaveBeenCalledTimes(1) expect(listener2).toHaveBeenCalledTimes(1) }) }) })