import { expect, test, describe, beforeEach, afterEach } from "vitest"; import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; import { homedir, tmpdir } from "node:os"; import path from "node:path"; import { getConfigDir, getMnemonicsDir, getDataDir, getWalletConfigPath, resolveMnemonicFilePath, } from "../../src/utils/paths"; describe("paths utilities", () => { describe("getConfigDir", () => { test("returns path under ~/.config/xo-cli", () => { const configDir = getConfigDir(); expect(configDir).toBe(path.join(homedir(), ".config", "xo-cli")); }); test("creates the directory if it does not exist", () => { const configDir = getConfigDir(); expect(existsSync(configDir)).toBe(true); }); }); describe("getMnemonicsDir", () => { test("returns path under config dir", () => { const mnemonicsDir = getMnemonicsDir(); expect(mnemonicsDir).toBe(path.join(homedir(), ".config", "xo-cli", "mnemonics")); }); test("creates the directory if it does not exist", () => { const mnemonicsDir = getMnemonicsDir(); expect(existsSync(mnemonicsDir)).toBe(true); }); }); describe("getDataDir", () => { test("returns path under config dir", () => { const dataDir = getDataDir(); expect(dataDir).toBe(path.join(homedir(), ".config", "xo-cli", "data")); }); test("creates the directory if it does not exist", () => { const dataDir = getDataDir(); expect(existsSync(dataDir)).toBe(true); }); }); describe("getWalletConfigPath", () => { test("returns .wallet file path under config dir", () => { const walletConfigPath = getWalletConfigPath(); expect(walletConfigPath).toBe(path.join(homedir(), ".config", "xo-cli", ".wallet")); }); }); describe("resolveMnemonicFilePath (global)", () => { let tempDir: string; beforeEach(() => { tempDir = path.join(tmpdir(), `xo-cli-paths-test-${Date.now()}`); mkdirSync(tempDir, { recursive: true }); }); afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); }); test("resolves absolute path when file exists", () => { const filePath = path.join(tempDir, "mnemonic-test"); writeFileSync(filePath, "test"); const resolved = resolveMnemonicFilePath(filePath); expect(resolved).toBe(filePath); }); test("resolves path relative to cwd when file exists", () => { const originalCwd = process.cwd(); process.chdir(tempDir); try { writeFileSync(path.join(tempDir, "mnemonic-cwd-test"), "test"); const resolved = resolveMnemonicFilePath("mnemonic-cwd-test"); expect(resolved).toBe(path.join(tempDir, "mnemonic-cwd-test")); } finally { process.chdir(originalCwd); } }); test("resolves from global mnemonics dir when file exists there", () => { const mnemonicsDir = getMnemonicsDir(); const testFile = path.join(mnemonicsDir, "mnemonic-global-test"); try { writeFileSync(testFile, "test"); const resolved = resolveMnemonicFilePath("mnemonic-global-test"); expect(resolved).toBe(testFile); } finally { if (existsSync(testFile)) { rmSync(testFile); } } }); test("throws when file not found anywhere", () => { expect(() => resolveMnemonicFilePath("nonexistent-mnemonic-file-xyz")).toThrow( /Mnemonic file not found/, ); }); test("does not resolve absolute path if file does not exist", () => { const nonExistentPath = "/nonexistent/path/mnemonic-test"; expect(() => resolveMnemonicFilePath(nonExistentPath)).toThrow( /Mnemonic file not found/, ); }); }); describe("path hierarchy", () => { test("mnemonics dir is under config dir", () => { const configDir = getConfigDir(); const mnemonicsDir = getMnemonicsDir(); expect(mnemonicsDir.startsWith(configDir)).toBe(true); }); test("data dir is under config dir", () => { const configDir = getConfigDir(); const dataDir = getDataDir(); expect(dataDir.startsWith(configDir)).toBe(true); }); test("wallet config is under config dir", () => { const configDir = getConfigDir(); const walletConfig = getWalletConfigPath(); expect(walletConfig.startsWith(configDir)).toBe(true); }); }); });