add deep equality checks and naming fixes

This commit is contained in:
Venkatesan Ravi
2025-11-03 12:47:54 -08:00
parent 89ab32dd67
commit 1b99b9d1a1
18 changed files with 271 additions and 127 deletions

View File

@@ -25,7 +25,7 @@ design principle validated through comprehensive integration testing.
- **Build**: `npm run build` - Compiles TypeScript using esbuild
- **Development**: `npm run dev` - Runs the CLI directly with tsx
- **Test**: `npm run test` - Runs Vitest test suite (42 tests total)
- **Test**: `npm run test` - Runs Vitest test suite (64 tests total)
- **Type checking**: `npm run typecheck` - Runs TypeScript compiler in check
mode
- **Generate types**: `npm run typegen` - Generates TypeScript types from
@@ -228,6 +228,61 @@ operation alongside other management tools.
with tests
6. **Respect authentication**: Always ask for API key, never store it
## Naming Convention Rules
**CRITICAL**: Follow this exact naming pattern for all OpenAPI schema
integrations.
For any OpenAPI schema `components["schemas"]["XyzAbc"]`, create:
1. **`XyzAbcSchema`** - Direct type mapping from OpenAPI schema
```typescript
export type XyzAbcSchema = components["schemas"]["XyzAbc"];
```
2. **`XyzAbcConfig`** - User-facing config interface
```typescript
export interface XyzAbcConfig {
someField?: boolean;
}
```
3. **`XyzAbcConfigSchema`** - Zod validation schema for config
```typescript
export const XyzAbcConfigSchema = z
.object({
someField: z.boolean().optional(),
})
.strict();
```
4. **`mapXyzAbcConfigToSchema`** - Mapper function from config to schema
```typescript
export function mapXyzAbcConfigToSchema(
desired: XyzAbcConfig,
): Partial<XyzAbcSchema> { ... }
```
5. **Variable names** - Must match the type name
```typescript
const currentXyzAbcSchema: XyzAbcSchema = ...;
const updatedXyzAbcSchema: XyzAbcSchema = ...;
```
**Example**: For `components["schemas"]["EncodingOptions"]`:
- ✅ `EncodingOptionsSchema`, `EncodingOptionsConfig`,
`EncodingOptionsConfigSchema`
- ✅ `mapEncodingOptionsConfigToSchema`
- ✅ `currentEncodingOptionsSchema`, `updatedEncodingOptionsSchema`
**Never deviate from this pattern** - it ensures consistent, predictable naming
across the entire codebase.
## Important Reminders
- **Never create files unless absolutely necessary** - prefer editing existing

View File

@@ -252,10 +252,10 @@ nix build .#
**High Priority:**
- [ ] **Encoding Configuration**: Transcoding settings, hardware acceleration,
codec preferences
- [ ] **Deep Equality Checking**: Replace JSON.stringify with proper deep
comparison
- [x] **Encoding Configuration**: Basic transcoding settings
(enableHardwareEncoding)
- [x] **Deep Equality Checking**: Replaced JSON.stringify with fast-equals
library
- [ ] **Structured Error Handling**: Better error types and API response details
**Medium Priority:**

View File

@@ -8,3 +8,6 @@ system:
enabled: true
trickplayOptions:
enableHwAcceleration: true
enableHwEncoding: true
encoding:
enableHardwareEncoding: true

View File

@@ -44,7 +44,7 @@ pkgs.stdenvNoCC.mkDerivation (finalAttrs: {
pnpmDeps = pkgs.pnpm.fetchDeps {
fetcherVersion = 1;
hash = "sha256-LjdZDFenfylIpKxRpVmPUten/1IyL/cmI6QjDfcmfDc=";
hash = "sha256-EFshNgnzsgnJnXuhdbyZKsMQ2W7LWA58jNQEzJ7TTwU=";
inherit (finalAttrs) pname src version;
};

View File

@@ -13,6 +13,7 @@
"dependencies": {
"commander": "^14.0.2",
"dotenv": "^17.2.3",
"fast-equals": "^5.3.2",
"openapi-fetch": "^0.15.0",
"undici": "^7.16.0",
"yaml": "^2.8.1",

12
pnpm-lock.yaml generated
View File

@@ -13,6 +13,9 @@ importers:
dotenv:
specifier: ^17.2.3
version: 17.2.3
fast-equals:
specifier: ^5.3.2
version: 5.3.2
openapi-fetch:
specifier: ^0.15.0
version: 0.15.0
@@ -1096,6 +1099,13 @@ packages:
integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
}
fast-equals@5.3.2:
resolution:
{
integrity: sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==,
}
engines: { node: ">=6.0.0" }
fast-glob@3.3.3:
resolution:
{
@@ -2439,6 +2449,8 @@ snapshots:
fast-deep-equal@3.1.3: {}
fast-equals@5.3.2: {}
fast-glob@3.3.3:
dependencies:
"@nodelib/fs.stat": 2.0.5

View File

@@ -1,13 +1,13 @@
import type { ServerConfigurationSchema } from "../types/schema/system";
import type { EncodingConfigurationSchema } from "../types/schema/encoding";
import type { EncodingOptionsSchema } from "../types/schema/encoding";
export interface JellyfinClient {
getSystemConfiguration(): Promise<ServerConfigurationSchema>;
updateSystemConfiguration(
body: Partial<ServerConfigurationSchema>,
): Promise<void>;
getEncodingConfiguration(): Promise<EncodingConfigurationSchema>;
getEncodingConfiguration(): Promise<EncodingOptionsSchema>;
updateEncodingConfiguration(
body: Partial<EncodingConfigurationSchema>,
body: Partial<EncodingOptionsSchema>,
): Promise<void>;
}

View File

@@ -1,5 +1,5 @@
import type { ServerConfigurationSchema } from "../types/schema/system";
import type { EncodingConfigurationSchema } from "../types/schema/encoding";
import type { EncodingOptionsSchema } from "../types/schema/encoding";
import type { JellyfinClient } from "./jellyfin.types";
import { makeClient } from "./client";
import type { paths } from "../../generated/schema";
@@ -44,7 +44,7 @@ export function createJellyfinClient(
}
},
async getEncodingConfiguration(): Promise<EncodingConfigurationSchema> {
async getEncodingConfiguration(): Promise<EncodingOptionsSchema> {
// eslint-disable-next-line @typescript-eslint/typedef
const res = await client.GET("/System/Configuration/{key}", {
params: { path: { key: "encoding" } },
@@ -56,11 +56,11 @@ export function createJellyfinClient(
);
}
return res.data as EncodingConfigurationSchema;
return res.data as EncodingOptionsSchema;
},
async updateEncodingConfiguration(
body: Partial<EncodingConfigurationSchema>,
body: Partial<EncodingOptionsSchema>,
): Promise<void> {
// eslint-disable-next-line @typescript-eslint/typedef
const res = await client.POST("/System/Configuration/{key}", {

View File

@@ -1,11 +1,11 @@
import { logger } from "../lib/logger";
import { mapEncodingConfigurationConfigToSchema } from "../mappers/encoding";
import { type EncodingConfig } from "../types/config/encoding";
import { type EncodingConfigurationSchema } from "../types/schema/encoding";
import { mapEncodingOptionsConfigToSchema } from "../mappers/encoding";
import { type EncodingOptionsConfig } from "../types/config/encoding";
import { type EncodingOptionsSchema } from "../types/schema/encoding";
function hasEnableHardwareEncodingChanged(
current: EncodingConfigurationSchema,
desired: EncodingConfig,
current: EncodingOptionsSchema,
desired: EncodingOptionsConfig,
): boolean {
if (desired.enableHardwareEncoding === undefined) return false;
@@ -16,11 +16,11 @@ function hasEnableHardwareEncodingChanged(
}
export function applyEncoding(
current: EncodingConfigurationSchema,
desired: EncodingConfig,
): EncodingConfigurationSchema {
const patch: Partial<EncodingConfigurationSchema> =
mapEncodingConfigurationConfigToSchema(desired);
current: EncodingOptionsSchema,
desired: EncodingOptionsConfig,
): EncodingOptionsSchema {
const patch: Partial<EncodingOptionsSchema> =
mapEncodingOptionsConfigToSchema(desired);
if (hasEnableHardwareEncodingChanged(current, desired)) {
logger.info(
@@ -28,7 +28,7 @@ export function applyEncoding(
);
}
const out: EncodingConfigurationSchema = { ...current };
const out: EncodingOptionsSchema = { ...current };
if ("EnableHardwareEncoding" in patch) {
out.EnableHardwareEncoding = patch.EnableHardwareEncoding;

View File

@@ -1,10 +1,10 @@
import { type EncodingConfig } from "../types/config/encoding";
import { type EncodingConfigurationSchema } from "../types/schema/encoding";
import { type EncodingOptionsConfig } from "../types/config/encoding";
import { type EncodingOptionsSchema } from "../types/schema/encoding";
export function mapEncodingConfigurationConfigToSchema(
desired: EncodingConfig,
): Partial<EncodingConfigurationSchema> {
const out: Partial<EncodingConfigurationSchema> = {};
export function mapEncodingOptionsConfigToSchema(
desired: EncodingOptionsConfig,
): Partial<EncodingOptionsSchema> {
const out: Partial<EncodingOptionsSchema> = {};
if (typeof desired.enableHardwareEncoding !== "undefined") {
out.EnableHardwareEncoding = desired.enableHardwareEncoding;

View File

@@ -1,9 +1,10 @@
import { promises as fs } from "fs";
import YAML from "yaml";
import { deepEqual } from "fast-equals";
import { applySystem } from "../apply/system";
import { applyEncoding } from "../apply/encoding";
import { type ServerConfigurationSchema } from "../types/schema/system";
import { type EncodingConfigurationSchema } from "../types/schema/encoding";
import { type EncodingOptionsSchema } from "../types/schema/encoding";
import { createJellyfinClient } from "../api/jellyfin_client";
import { type JellyfinClient } from "../api/jellyfin.types";
import {
@@ -35,19 +36,21 @@ export async function runPipeline(path: string): Promise<void> {
);
// Handle system configuration
const currentSystem: ServerConfigurationSchema =
const currentServerConfigurationSchema: ServerConfigurationSchema =
await jellyfinClient.getSystemConfiguration();
const updatedSystem: ServerConfigurationSchema = applySystem(
currentSystem,
cfg.system,
);
const updatedServerConfigurationSchema: ServerConfigurationSchema =
applySystem(currentServerConfigurationSchema, cfg.system);
const systemSame: boolean =
JSON.stringify(updatedSystem) === JSON.stringify(currentSystem);
if (!systemSame) {
const isSystemSame: boolean = deepEqual(
updatedServerConfigurationSchema,
currentServerConfigurationSchema,
);
if (!isSystemSame) {
console.log("→ updating system config");
await jellyfinClient.updateSystemConfiguration(updatedSystem);
await jellyfinClient.updateSystemConfiguration(
updatedServerConfigurationSchema,
);
console.log("✓ updated system config");
} else {
console.log("✓ system config already up to date");
@@ -55,19 +58,23 @@ export async function runPipeline(path: string): Promise<void> {
// Handle encoding configuration if provided
if (cfg.encoding) {
const currentEncoding: EncodingConfigurationSchema =
const currentEncodingOptionsSchema: EncodingOptionsSchema =
await jellyfinClient.getEncodingConfiguration();
const updatedEncoding: EncodingConfigurationSchema = applyEncoding(
currentEncoding,
const updatedEncodingOptionsSchema: EncodingOptionsSchema = applyEncoding(
currentEncodingOptionsSchema,
cfg.encoding,
);
const encodingSame: boolean =
JSON.stringify(updatedEncoding) === JSON.stringify(currentEncoding);
if (!encodingSame) {
const isEncodingSame: boolean = deepEqual(
updatedEncodingOptionsSchema,
currentEncodingOptionsSchema,
);
if (!isEncodingSame) {
console.log("→ updating encoding config");
await jellyfinClient.updateEncodingConfiguration(updatedEncoding);
await jellyfinClient.updateEncodingConfiguration(
updatedEncodingOptionsSchema,
);
console.log("✓ updated encoding config");
} else {
console.log("✓ encoding config already up to date");

View File

@@ -1,3 +1,3 @@
export interface EncodingConfig {
export interface EncodingOptionsConfig {
enableHardwareEncoding?: boolean;
}

View File

@@ -1,4 +1,3 @@
import type { components } from "../../../generated/schema";
export type EncodingConfigurationSchema =
components["schemas"]["EncodingOptions"];
export type EncodingOptionsSchema = components["schemas"]["EncodingOptions"];

View File

@@ -32,7 +32,7 @@ export const SystemConfigSchema: z.ZodObject<{
})
.strict();
export const EncodingConfigSchema: z.ZodObject<{
export const EncodingOptionsConfigSchema: z.ZodObject<{
enableHardwareEncoding: z.ZodOptional<z.ZodBoolean>;
}> = z
.object({
@@ -44,13 +44,13 @@ export const RootConfigSchema: z.ZodObject<{
version: z.ZodNumber;
base_url: ReturnType<typeof z.url>;
system: typeof SystemConfigSchema;
encoding: z.ZodOptional<typeof EncodingConfigSchema>;
encoding: z.ZodOptional<typeof EncodingOptionsConfigSchema>;
}> = z
.object({
version: z.number().int().positive("Version must be a positive integer"),
base_url: z.url({ message: "Base URL must be a valid URL" }),
system: SystemConfigSchema,
encoding: EncodingConfigSchema.optional(),
encoding: EncodingOptionsConfigSchema.optional(),
})
.strict();
@@ -61,5 +61,7 @@ export type ValidatedTrickplayOptionsConfig = z.infer<
typeof TrickplayOptionsConfigSchema
>;
export type ValidatedSystemConfig = z.infer<typeof SystemConfigSchema>;
export type ValidatedEncodingConfig = z.infer<typeof EncodingConfigSchema>;
export type ValidatedEncodingOptionsConfig = z.infer<
typeof EncodingOptionsConfigSchema
>;
export type ValidatedRootConfig = z.infer<typeof RootConfigSchema>;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
import { applyEncoding } from "../../src/apply/encoding";
import { type EncodingConfig } from "../../src/types/config/encoding";
import { type EncodingConfigurationSchema } from "../../src/types/schema/encoding";
import { type EncodingOptionsConfig } from "../../src/types/config/encoding";
import { type EncodingOptionsSchema } from "../../src/types/schema/encoding";
import * as loggerModule from "../../src/lib/logger";
// Mock the logger
@@ -21,21 +21,18 @@ describe("apply/encoding", () => {
describe("applyEncoding", () => {
it("should update EnableHardwareEncoding when enableHardwareEncoding changes from false to true", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: false,
EncodingThreadCount: -1,
TranscodingTempPath: "/tmp",
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {
const desired: EncodingOptionsConfig = {
enableHardwareEncoding: true,
};
// Act
const result: EncodingConfigurationSchema = applyEncoding(
current,
desired,
);
const result: EncodingOptionsSchema = applyEncoding(current, desired);
// Assert
expect(result.EnableHardwareEncoding).toBe(true);
@@ -45,20 +42,17 @@ describe("apply/encoding", () => {
it("should update EnableHardwareEncoding when enableHardwareEncoding changes from true to false", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: true,
EncodingThreadCount: 4,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {
const desired: EncodingOptionsConfig = {
enableHardwareEncoding: false,
};
// Act
const result: EncodingConfigurationSchema = applyEncoding(
current,
desired,
);
const result: EncodingOptionsSchema = applyEncoding(current, desired);
// Assert
expect(result.EnableHardwareEncoding).toBe(false);
@@ -67,18 +61,15 @@ describe("apply/encoding", () => {
it("should not modify EnableHardwareEncoding when enableHardwareEncoding is undefined", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: true,
EncodingThreadCount: 2,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {};
const desired: EncodingOptionsConfig = {};
// Act
const result: EncodingConfigurationSchema = applyEncoding(
current,
desired,
);
const result: EncodingOptionsSchema = applyEncoding(current, desired);
// Assert
expect(result.EnableHardwareEncoding).toBe(true); // Should remain unchanged
@@ -87,20 +78,17 @@ describe("apply/encoding", () => {
it("should not modify EnableHardwareEncoding when value is the same", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: true,
EncodingThreadCount: 1,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {
const desired: EncodingOptionsConfig = {
enableHardwareEncoding: true,
};
// Act
const result: EncodingConfigurationSchema = applyEncoding(
current,
desired,
);
const result: EncodingOptionsSchema = applyEncoding(current, desired);
// Assert
expect(result.EnableHardwareEncoding).toBe(true);
@@ -109,11 +97,11 @@ describe("apply/encoding", () => {
it("should log when EnableHardwareEncoding changes", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: false,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {
const desired: EncodingOptionsConfig = {
enableHardwareEncoding: true,
};
@@ -133,11 +121,11 @@ describe("apply/encoding", () => {
it("should not log when EnableHardwareEncoding does not change", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: true,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {
const desired: EncodingOptionsConfig = {
enableHardwareEncoding: true,
};
@@ -155,11 +143,11 @@ describe("apply/encoding", () => {
it("should not log when enableHardwareEncoding is undefined", () => {
// Arrange
const current: EncodingConfigurationSchema = {
const current: EncodingOptionsSchema = {
EnableHardwareEncoding: true,
} as EncodingConfigurationSchema;
} as EncodingOptionsSchema;
const desired: EncodingConfig = {};
const desired: EncodingOptionsConfig = {};
const loggerSpy: Mock<(msg: string) => void> = vi.spyOn(
loggerModule.logger,

View File

@@ -0,0 +1,77 @@
import { describe, it, expect } from "vitest";
import { deepEqual } from "fast-equals";
describe("lib/deep-equality", () => {
describe("deepEqual vs JSON.stringify", () => {
it("should handle objects with different property order correctly", () => {
// Arrange
const obj1: { a: number; b: number; c: number } = { a: 1, b: 2, c: 3 };
const obj2: { c: number; b: number; a: number } = { c: 3, b: 2, a: 1 };
// Act & Assert
// deep equality should correctly identify these as equal
expect(deepEqual(obj1, obj2)).toBe(true);
// JSON.stringify would incorrectly identify these as different
expect(JSON.stringify(obj1) === JSON.stringify(obj2)).toBe(false);
});
it("should handle undefined values correctly", () => {
// Arrange
const obj1: { a: number; b: undefined } = { a: 1, b: undefined };
const obj2: { a: number; b: undefined } = { a: 1, b: undefined };
// Act & Assert
// deep equality should correctly handle undefined
expect(deepEqual(obj1, obj2)).toBe(true);
// JSON.stringify would not serialize undefined values at all
expect(JSON.stringify(obj1) === JSON.stringify(obj2)).toBe(true);
// But JSON.stringify would miss differences involving undefined
const obj3: { a: number } = { a: 1 };
expect(deepEqual(obj1, obj3)).toBe(false);
expect(JSON.stringify(obj1) === JSON.stringify(obj3)).toBe(true); // false positive!
});
it("should handle nested objects correctly", () => {
// Arrange
const obj1: {
system: { enableMetrics: boolean };
encoding: { enableHardwareEncoding: boolean };
} = {
system: { enableMetrics: true },
encoding: { enableHardwareEncoding: false },
};
const obj2: {
encoding: { enableHardwareEncoding: boolean };
system: { enableMetrics: boolean };
} = {
encoding: { enableHardwareEncoding: false },
system: { enableMetrics: true },
};
// Act & Assert
expect(deepEqual(obj1, obj2)).toBe(true);
expect(JSON.stringify(obj1) === JSON.stringify(obj2)).toBe(false);
});
it("should handle Date objects correctly", () => {
// Arrange
const date: Date = new Date("2024-01-01");
const obj1: { timestamp: Date } = { timestamp: date };
const obj2: { timestamp: Date } = { timestamp: new Date("2024-01-01") };
// Act & Assert
expect(deepEqual(obj1, obj2)).toBe(true);
expect(JSON.stringify(obj1) === JSON.stringify(obj2)).toBe(true); // works but converts to string
// But deepEqual preserves type information
const obj3: { timestamp: string } = {
timestamp: "2024-01-01T00:00:00.000Z",
};
expect(deepEqual(obj1, obj3)).toBe(false); // correctly different types
expect(JSON.stringify(obj1) === JSON.stringify(obj3)).toBe(true); // false positive!
});
});
});

View File

@@ -1,19 +1,19 @@
import { describe, it, expect } from "vitest";
import { mapEncodingConfigurationConfigToSchema } from "../../src/mappers/encoding";
import { type EncodingConfig } from "../../src/types/config/encoding";
import { type EncodingConfigurationSchema } from "../../src/types/schema/encoding";
import { mapEncodingOptionsConfigToSchema } from "../../src/mappers/encoding";
import { type EncodingOptionsConfig } from "../../src/types/config/encoding";
import { type EncodingOptionsSchema } from "../../src/types/schema/encoding";
describe("mappers/encoding", () => {
describe("mapEncodingConfigurationConfigToSchema", () => {
describe("mapEncodingOptionsConfigToSchema", () => {
it("should map enableHardwareEncoding to EnableHardwareEncoding", () => {
// Arrange
const config: EncodingConfig = {
const config: EncodingOptionsConfig = {
enableHardwareEncoding: true,
};
// Act
const result: Partial<EncodingConfigurationSchema> =
mapEncodingConfigurationConfigToSchema(config);
const result: Partial<EncodingOptionsSchema> =
mapEncodingOptionsConfigToSchema(config);
// Assert
expect(result).toEqual({
@@ -23,13 +23,13 @@ describe("mappers/encoding", () => {
it("should map enableHardwareEncoding false to EnableHardwareEncoding false", () => {
// Arrange
const config: EncodingConfig = {
const config: EncodingOptionsConfig = {
enableHardwareEncoding: false,
};
// Act
const result: Partial<EncodingConfigurationSchema> =
mapEncodingConfigurationConfigToSchema(config);
const result: Partial<EncodingOptionsSchema> =
mapEncodingOptionsConfigToSchema(config);
// Assert
expect(result).toEqual({
@@ -39,11 +39,11 @@ describe("mappers/encoding", () => {
it("should return empty object when enableHardwareEncoding is undefined", () => {
// Arrange
const config: EncodingConfig = {};
const config: EncodingOptionsConfig = {};
// Act
const result: Partial<EncodingConfigurationSchema> =
mapEncodingConfigurationConfigToSchema(config);
const result: Partial<EncodingOptionsSchema> =
mapEncodingOptionsConfigToSchema(config);
// Assert
expect(result).toEqual({});
@@ -51,11 +51,11 @@ describe("mappers/encoding", () => {
it("should not include EnableHardwareEncoding when field is not provided", () => {
// Arrange
const config: EncodingConfig = {};
const config: EncodingOptionsConfig = {};
// Act
const result: Partial<EncodingConfigurationSchema> =
mapEncodingConfigurationConfigToSchema(config);
const result: Partial<EncodingOptionsSchema> =
mapEncodingOptionsConfigToSchema(config);
// Assert
expect(result).not.toHaveProperty("EnableHardwareEncoding");

View File

@@ -6,11 +6,11 @@ import {
SystemConfigSchema,
PluginRepositoryConfigSchema,
TrickplayOptionsConfigSchema,
EncodingConfigSchema,
EncodingOptionsConfigSchema,
type ValidatedPluginRepositoryConfig,
type ValidatedTrickplayOptionsConfig,
type ValidatedSystemConfig,
type ValidatedEncodingConfig,
type ValidatedEncodingOptionsConfig,
type ValidatedRootConfig,
} from "../../src/validation/config";
@@ -358,14 +358,14 @@ describe("validation/config — RootConfigSchema", () => {
});
});
describe("validation/config — EncodingConfigSchema", () => {
describe("validation/config — EncodingOptionsConfigSchema", () => {
it("should validate empty encoding config", () => {
// Arrange
const validConfig: z.input<typeof EncodingConfigSchema> = {};
const validConfig: z.input<typeof EncodingOptionsConfigSchema> = {};
// Act
const result: ZodSafeParseResult<ValidatedEncodingConfig> =
EncodingConfigSchema.safeParse(validConfig);
const result: ZodSafeParseResult<ValidatedEncodingOptionsConfig> =
EncodingOptionsConfigSchema.safeParse(validConfig);
// Assert
expect(result.success).toBe(true);
@@ -376,13 +376,13 @@ describe("validation/config — EncodingConfigSchema", () => {
it("should validate encoding config with enableHardwareEncoding true", () => {
// Arrange
const validConfig: z.input<typeof EncodingConfigSchema> = {
const validConfig: z.input<typeof EncodingOptionsConfigSchema> = {
enableHardwareEncoding: true,
};
// Act
const result: ZodSafeParseResult<ValidatedEncodingConfig> =
EncodingConfigSchema.safeParse(validConfig);
const result: ZodSafeParseResult<ValidatedEncodingOptionsConfig> =
EncodingOptionsConfigSchema.safeParse(validConfig);
// Assert
expect(result.success).toBe(true);
@@ -393,13 +393,13 @@ describe("validation/config — EncodingConfigSchema", () => {
it("should validate encoding config with enableHardwareEncoding false", () => {
// Arrange
const validConfig: z.input<typeof EncodingConfigSchema> = {
const validConfig: z.input<typeof EncodingOptionsConfigSchema> = {
enableHardwareEncoding: false,
};
// Act
const result: ZodSafeParseResult<ValidatedEncodingConfig> =
EncodingConfigSchema.safeParse(validConfig);
const result: ZodSafeParseResult<ValidatedEncodingOptionsConfig> =
EncodingOptionsConfigSchema.safeParse(validConfig);
// Assert
expect(result.success).toBe(true);
@@ -410,14 +410,14 @@ describe("validation/config — EncodingConfigSchema", () => {
it("should reject non-boolean enableHardwareEncoding", () => {
// Arrange
const invalidConfig: z.input<typeof EncodingConfigSchema> = {
const invalidConfig: z.input<typeof EncodingOptionsConfigSchema> = {
// @ts-expect-error intentional bad type for test
enableHardwareEncoding: "true",
};
// Act
const result: ZodSafeParseResult<ValidatedEncodingConfig> =
EncodingConfigSchema.safeParse(invalidConfig);
const result: ZodSafeParseResult<ValidatedEncodingOptionsConfig> =
EncodingOptionsConfigSchema.safeParse(invalidConfig);
// Assert
expect(result.success).toBe(false);
@@ -425,15 +425,15 @@ describe("validation/config — EncodingConfigSchema", () => {
it("should reject extra fields due to strict mode", () => {
// Arrange
const invalidConfig: z.input<typeof EncodingConfigSchema> = {
const invalidConfig: z.input<typeof EncodingOptionsConfigSchema> = {
enableHardwareEncoding: true,
// @ts-expect-error intentional extra field for test
unknownField: "should not be allowed",
};
// Act
const result: ZodSafeParseResult<ValidatedEncodingConfig> =
EncodingConfigSchema.safeParse(invalidConfig);
const result: ZodSafeParseResult<ValidatedEncodingOptionsConfig> =
EncodingOptionsConfigSchema.safeParse(invalidConfig);
// Assert
expect(result.success).toBe(false);