A Deno-compatible AT Protocol OAuth client that serves as a drop-in replacement for @atproto/oauth-client-node
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 189 lines 6.0 kB view raw
1/** 2 * @fileoverview Tests for storage implementations 3 */ 4 5import { assertEquals } from "@std/assert"; 6import { LocalStorage, MemoryStorage } from "../src/storage.ts"; 7 8// Mock localStorage for testing 9class MockLocalStorage { 10 private store = new Map<string, string>(); 11 12 getItem(key: string): string | null { 13 return this.store.get(key) ?? null; 14 } 15 16 setItem(key: string, value: string): void { 17 this.store.set(key, value); 18 } 19 20 removeItem(key: string): void { 21 this.store.delete(key); 22 } 23 24 clear(): void { 25 this.store.clear(); 26 } 27} 28 29// Setup mock for LocalStorage tests 30const mockLocalStorage = new MockLocalStorage(); 31// @ts-ignore: Mock global for testing 32globalThis.localStorage = mockLocalStorage; 33 34Deno.test("MemoryStorage - Basic Operations", async (t) => { 35 const storage = new MemoryStorage(); 36 37 await t.step("should store and retrieve values", async () => { 38 await storage.set("test-key", { data: "test-value" }); 39 const result = await storage.get<{ data: string }>("test-key"); 40 assertEquals(result, { data: "test-value" }); 41 }); 42 43 await t.step("should return null for non-existent keys", async () => { 44 const result = await storage.get("non-existent"); 45 assertEquals(result, null); 46 }); 47 48 await t.step("should delete values", async () => { 49 await storage.set("delete-me", "test"); 50 await storage.delete("delete-me"); 51 const result = await storage.get("delete-me"); 52 assertEquals(result, null); 53 }); 54 55 await t.step("should clear all values", async () => { 56 await storage.set("key1", "value1"); 57 await storage.set("key2", "value2"); 58 storage.clear(); 59 assertEquals(await storage.get("key1"), null); 60 assertEquals(await storage.get("key2"), null); 61 }); 62}); 63 64Deno.test("MemoryStorage - TTL Functionality", async (t) => { 65 const storage = new MemoryStorage(); 66 67 await t.step("should store values with TTL", async () => { 68 await storage.set("ttl-key", "ttl-value", { ttl: 1 }); // 1 second TTL 69 const result = await storage.get("ttl-key"); 70 assertEquals(result, "ttl-value"); 71 }); 72 73 await t.step("should expire values after TTL", async () => { 74 await storage.set("expire-key", "expire-value", { ttl: 0.1 }); // 100ms TTL 75 76 // Should exist immediately 77 const beforeExpiry = await storage.get("expire-key"); 78 assertEquals(beforeExpiry, "expire-value"); 79 80 // Wait for expiry and check 81 await new Promise((resolve) => setTimeout(resolve, 150)); 82 const afterExpiry = await storage.get("expire-key"); 83 assertEquals(afterExpiry, null); 84 }); 85 86 await t.step("should store values without TTL indefinitely", async () => { 87 await storage.set("no-ttl", "persistent"); 88 89 // Wait a bit and verify it's still there 90 await new Promise((resolve) => setTimeout(resolve, 50)); 91 const result = await storage.get("no-ttl"); 92 assertEquals(result, "persistent"); 93 }); 94}); 95 96Deno.test("MemoryStorage - Data Types", async (t) => { 97 const storage = new MemoryStorage(); 98 99 await t.step("should handle strings", async () => { 100 await storage.set("string", "test-string"); 101 assertEquals(await storage.get("string"), "test-string"); 102 }); 103 104 await t.step("should handle numbers", async () => { 105 await storage.set("number", 42); 106 assertEquals(await storage.get("number"), 42); 107 }); 108 109 await t.step("should handle objects", async () => { 110 const obj = { key: "value", nested: { data: 123 } }; 111 await storage.set("object", obj); 112 assertEquals(await storage.get("object"), obj); 113 }); 114 115 await t.step("should handle arrays", async () => { 116 const arr = [1, "two", { three: 3 }]; 117 await storage.set("array", arr); 118 assertEquals(await storage.get("array"), arr); 119 }); 120 121 await t.step("should handle booleans", async () => { 122 await storage.set("bool-true", true); 123 await storage.set("bool-false", false); 124 assertEquals(await storage.get("bool-true"), true); 125 assertEquals(await storage.get("bool-false"), false); 126 }); 127}); 128 129Deno.test("LocalStorage - Basic Operations", async (t) => { 130 const storage = new LocalStorage(); 131 132 // Clear mock storage before each test 133 mockLocalStorage.clear(); 134 135 await t.step("should store and retrieve values", async () => { 136 await storage.set("local-key", { data: "local-value" }); 137 const result = await storage.get<{ data: string }>("local-key"); 138 assertEquals(result, { data: "local-value" }); 139 }); 140 141 await t.step("should return null for non-existent keys", async () => { 142 const result = await storage.get("non-existent"); 143 assertEquals(result, null); 144 }); 145 146 await t.step("should delete values", async () => { 147 await storage.set("delete-local", "test"); 148 await storage.delete("delete-local"); 149 const result = await storage.get("delete-local"); 150 assertEquals(result, null); 151 }); 152}); 153 154Deno.test("LocalStorage - TTL Functionality", async (t) => { 155 const storage = new LocalStorage(); 156 mockLocalStorage.clear(); 157 158 await t.step("should store values with TTL", async () => { 159 await storage.set("ttl-local", "ttl-value", { ttl: 1 }); 160 const result = await storage.get("ttl-local"); 161 assertEquals(result, "ttl-value"); 162 }); 163 164 await t.step("should expire values after TTL", async () => { 165 await storage.set("expire-local", "expire-value", { ttl: 0.1 }); // 100ms TTL 166 167 // Should exist immediately 168 const beforeExpiry = await storage.get("expire-local"); 169 assertEquals(beforeExpiry, "expire-value"); 170 171 // Wait for expiry and check 172 await new Promise((resolve) => setTimeout(resolve, 150)); 173 const afterExpiry = await storage.get("expire-local"); 174 assertEquals(afterExpiry, null); 175 }); 176}); 177 178Deno.test("LocalStorage - Error Handling", async (t) => { 179 const storage = new LocalStorage(); 180 mockLocalStorage.clear(); 181 182 await t.step("should handle JSON parse errors gracefully", async () => { 183 // Manually set invalid JSON in mock storage 184 mockLocalStorage.setItem("invalid-json", "invalid-json-data"); 185 186 const result = await storage.get("invalid-json"); 187 assertEquals(result, null); 188 }); 189});