diff --git a/src/shared/entry-status.test.ts b/src/shared/entry-status.test.ts new file mode 100644 index 00000000000..88913913011 --- /dev/null +++ b/src/shared/entry-status.test.ts @@ -0,0 +1,132 @@ +import { afterEach, describe, expect, it } from "vitest"; +import { + evaluateEntryMetadataRequirements, + evaluateEntryMetadataRequirementsForCurrentPlatform, + evaluateEntryRequirementsForCurrentPlatform, +} from "./entry-status.js"; + +const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, "platform"); + +function setPlatform(platform: NodeJS.Platform): void { + Object.defineProperty(process, "platform", { + value: platform, + configurable: true, + }); +} + +afterEach(() => { + if (originalPlatformDescriptor) { + Object.defineProperty(process, "platform", originalPlatformDescriptor); + } +}); + +describe("shared/entry-status", () => { + it("combines metadata presentation fields with evaluated requirements", () => { + const result = evaluateEntryMetadataRequirements({ + always: false, + metadata: { + emoji: "🦀", + homepage: "https://openclaw.ai", + requires: { + bins: ["bun"], + anyBins: ["ffmpeg", "sox"], + env: ["OPENCLAW_TOKEN"], + config: ["gateway.bind"], + }, + os: ["darwin"], + }, + frontmatter: { + emoji: "🙂", + homepage: "https://docs.openclaw.ai", + }, + hasLocalBin: (bin) => bin === "bun", + localPlatform: "linux", + remote: { + hasAnyBin: (bins) => bins.includes("sox"), + }, + isEnvSatisfied: () => false, + isConfigSatisfied: (path) => path === "gateway.bind", + }); + + expect(result).toEqual({ + emoji: "🦀", + homepage: "https://openclaw.ai", + required: { + bins: ["bun"], + anyBins: ["ffmpeg", "sox"], + env: ["OPENCLAW_TOKEN"], + config: ["gateway.bind"], + os: ["darwin"], + }, + missing: { + bins: [], + anyBins: [], + env: ["OPENCLAW_TOKEN"], + config: [], + os: ["darwin"], + }, + requirementsSatisfied: false, + configChecks: [{ path: "gateway.bind", satisfied: true }], + }); + }); + + it("uses process.platform in the current-platform wrapper", () => { + setPlatform("darwin"); + + const result = evaluateEntryMetadataRequirementsForCurrentPlatform({ + always: false, + metadata: { + os: ["darwin"], + }, + hasLocalBin: () => false, + isEnvSatisfied: () => true, + isConfigSatisfied: () => true, + }); + + expect(result.requirementsSatisfied).toBe(true); + expect(result.missing.os).toEqual([]); + }); + + it("pulls metadata and frontmatter from entry objects in the entry wrapper", () => { + setPlatform("linux"); + + const result = evaluateEntryRequirementsForCurrentPlatform({ + always: true, + entry: { + metadata: { + requires: { + bins: ["missing-bin"], + }, + }, + frontmatter: { + website: " https://docs.openclaw.ai ", + emoji: "🙂", + }, + }, + hasLocalBin: () => false, + isEnvSatisfied: () => false, + isConfigSatisfied: () => false, + }); + + expect(result).toEqual({ + emoji: "🙂", + homepage: "https://docs.openclaw.ai", + required: { + bins: ["missing-bin"], + anyBins: [], + env: [], + config: [], + os: [], + }, + missing: { + bins: [], + anyBins: [], + env: [], + config: [], + os: [], + }, + requirementsSatisfied: true, + configChecks: [], + }); + }); +}); diff --git a/src/shared/net/ipv4.test.ts b/src/shared/net/ipv4.test.ts new file mode 100644 index 00000000000..a6d7ab2f84e --- /dev/null +++ b/src/shared/net/ipv4.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { validateDottedDecimalIPv4Input, validateIPv4AddressInput } from "./ipv4.js"; + +describe("shared/net/ipv4", () => { + it("requires a value for custom bind mode", () => { + expect(validateDottedDecimalIPv4Input(undefined)).toBe( + "IP address is required for custom bind mode", + ); + expect(validateDottedDecimalIPv4Input("")).toBe("IP address is required for custom bind mode"); + }); + + it("accepts canonical dotted-decimal ipv4 only", () => { + expect(validateDottedDecimalIPv4Input("192.168.1.100")).toBeUndefined(); + expect(validateDottedDecimalIPv4Input("0177.0.0.1")).toBe( + "Invalid IPv4 address (e.g., 192.168.1.100)", + ); + expect(validateDottedDecimalIPv4Input("example.com")).toBe( + "Invalid IPv4 address (e.g., 192.168.1.100)", + ); + }); + + it("keeps the backward-compatible alias wired to the same validation", () => { + expect(validateIPv4AddressInput("192.168.1.100")).toBeUndefined(); + expect(validateIPv4AddressInput("bad-ip")).toBe("Invalid IPv4 address (e.g., 192.168.1.100)"); + }); +});