feat(schema/result-types): define analysis result TypeBox schemas
This commit is contained in:
@@ -1 +1,99 @@
|
|||||||
// RiskPathResult, DecomposeResult, WorkflowCostResult, RiskDistributionResult schemas
|
import { Type, type Static } from "@alkdev/typebox";
|
||||||
|
|
||||||
|
// --- RiskPathResult ---
|
||||||
|
|
||||||
|
/** Result of finding the highest-risk path through the graph. */
|
||||||
|
export const RiskPathResult = Type.Object({
|
||||||
|
path: Type.Array(Type.String()),
|
||||||
|
totalRisk: Type.Number(),
|
||||||
|
});
|
||||||
|
/** { path: string[], totalRisk: number } */
|
||||||
|
export type RiskPathResult = Static<typeof RiskPathResult>;
|
||||||
|
|
||||||
|
// --- DecomposeResult ---
|
||||||
|
|
||||||
|
/** Result of decomposing whether a task should be split. */
|
||||||
|
export const DecomposeResult = Type.Object({
|
||||||
|
shouldDecompose: Type.Boolean(),
|
||||||
|
reasons: Type.Array(Type.String()),
|
||||||
|
});
|
||||||
|
/** { shouldDecompose: boolean, reasons: string[] } */
|
||||||
|
export type DecomposeResult = Static<typeof DecomposeResult>;
|
||||||
|
|
||||||
|
// --- WorkflowCostOptions ---
|
||||||
|
|
||||||
|
/** Options for the workflowCost analysis function. */
|
||||||
|
export const WorkflowCostOptions = Type.Object({
|
||||||
|
includeCompleted: Type.Optional(Type.Boolean()),
|
||||||
|
limit: Type.Optional(Type.Number()),
|
||||||
|
propagationMode: Type.Optional(
|
||||||
|
Type.Union([Type.Literal("independent"), Type.Literal("dag-propagate")])
|
||||||
|
),
|
||||||
|
defaultQualityRetention: Type.Optional(Type.Number()),
|
||||||
|
});
|
||||||
|
/** Options for workflowCost analysis */
|
||||||
|
export type WorkflowCostOptions = Static<typeof WorkflowCostOptions>;
|
||||||
|
|
||||||
|
// --- WorkflowCostResult ---
|
||||||
|
|
||||||
|
/** Per-task entry within WorkflowCostResult.tasks */
|
||||||
|
const WorkflowCostTaskEntry = Type.Object({
|
||||||
|
taskId: Type.String(),
|
||||||
|
name: Type.String(),
|
||||||
|
ev: Type.Number(),
|
||||||
|
pIntrinsic: Type.Number(),
|
||||||
|
pEffective: Type.Number(),
|
||||||
|
probability: Type.Number(),
|
||||||
|
scopeCost: Type.Number(),
|
||||||
|
impactWeight: Type.Number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Result of the workflowCost analysis function. */
|
||||||
|
export const WorkflowCostResult = Type.Object({
|
||||||
|
tasks: Type.Array(WorkflowCostTaskEntry),
|
||||||
|
totalEv: Type.Number(),
|
||||||
|
averageEv: Type.Number(),
|
||||||
|
propagationMode: Type.Union([
|
||||||
|
Type.Literal("independent"),
|
||||||
|
Type.Literal("dag-propagate"),
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
/** Result of workflowCost analysis */
|
||||||
|
export type WorkflowCostResult = Static<typeof WorkflowCostResult>;
|
||||||
|
|
||||||
|
// --- EvConfig ---
|
||||||
|
|
||||||
|
/** Configuration for calculateTaskEv with sensible defaults. */
|
||||||
|
export const EvConfig = Type.Object({
|
||||||
|
retries: Type.Optional(Type.Number({ default: 0 })),
|
||||||
|
fallbackCost: Type.Optional(Type.Number({ default: 0 })),
|
||||||
|
timeLost: Type.Optional(Type.Number({ default: 0 })),
|
||||||
|
valueRate: Type.Optional(Type.Number({ default: 0 })),
|
||||||
|
});
|
||||||
|
/** Configuration for expected value calculation */
|
||||||
|
export type EvConfig = Static<typeof EvConfig>;
|
||||||
|
|
||||||
|
// --- EvResult ---
|
||||||
|
|
||||||
|
/** Result of the calculateTaskEv function. */
|
||||||
|
export const EvResult = Type.Object({
|
||||||
|
ev: Type.Number(),
|
||||||
|
pSuccess: Type.Number(),
|
||||||
|
expectedRetries: Type.Number(),
|
||||||
|
});
|
||||||
|
/** { ev: number, pSuccess: number, expectedRetries: number } */
|
||||||
|
export type EvResult = Static<typeof EvResult>;
|
||||||
|
|
||||||
|
// --- RiskDistributionResult ---
|
||||||
|
|
||||||
|
/** Distribution of tasks by risk level. */
|
||||||
|
export const RiskDistributionResult = Type.Object({
|
||||||
|
trivial: Type.Array(Type.String()),
|
||||||
|
low: Type.Array(Type.String()),
|
||||||
|
medium: Type.Array(Type.String()),
|
||||||
|
high: Type.Array(Type.String()),
|
||||||
|
critical: Type.Array(Type.String()),
|
||||||
|
unspecified: Type.Array(Type.String()),
|
||||||
|
});
|
||||||
|
/** Distribution of tasks by risk level */
|
||||||
|
export type RiskDistributionResult = Static<typeof RiskDistributionResult>;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: schema/result-types
|
id: schema/result-types
|
||||||
name: Define analysis result TypeBox schemas (RiskPathResult, DecomposeResult, WorkflowCostResult, etc.)
|
name: Define analysis result TypeBox schemas (RiskPathResult, DecomposeResult, WorkflowCostResult, etc.)
|
||||||
status: pending
|
status: completed
|
||||||
depends_on:
|
depends_on:
|
||||||
- schema/enums
|
- schema/enums
|
||||||
scope: narrow
|
scope: narrow
|
||||||
@@ -16,7 +16,7 @@ Define all analysis function return type schemas in `src/schema/results.ts`. The
|
|||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [ ] `src/schema/results.ts` exports all result schemas and types:
|
- [x] `src/schema/results.ts` exports all result schemas and types:
|
||||||
- `RiskPathResult`: `{ path: string[], totalRisk: number }`
|
- `RiskPathResult`: `{ path: string[], totalRisk: number }`
|
||||||
- `DecomposeResult`: `{ shouldDecompose: boolean, reasons: string[] }`
|
- `DecomposeResult`: `{ shouldDecompose: boolean, reasons: string[] }`
|
||||||
- `WorkflowCostOptions`: `{ includeCompleted?, limit?, propagationMode?, defaultQualityRetention? }`
|
- `WorkflowCostOptions`: `{ includeCompleted?, limit?, propagationMode?, defaultQualityRetention? }`
|
||||||
@@ -24,9 +24,9 @@ Define all analysis function return type schemas in `src/schema/results.ts`. The
|
|||||||
- `EvConfig`: `{ retries?, fallbackCost?, timeLost?, valueRate? }` with defaults (0, 0, 0, 0)
|
- `EvConfig`: `{ retries?, fallbackCost?, timeLost?, valueRate? }` with defaults (0, 0, 0, 0)
|
||||||
- `EvResult`: `{ ev, pSuccess, expectedRetries }`
|
- `EvResult`: `{ ev, pSuccess, expectedRetries }`
|
||||||
- `RiskDistributionResult`: `{ trivial, low, medium, high, critical, unspecified }` — each `string[]`
|
- `RiskDistributionResult`: `{ trivial, low, medium, high, critical, unspecified }` — each `string[]`
|
||||||
- [ ] All schemas use `Static<typeof>` for type aliases, no manual interface definitions
|
- [x] All schemas use `Static<typeof>` for type aliases, no manual interface definitions
|
||||||
- [ ] `WorkflowCostOptions.propagationMode` is `Type.Union([Type.Literal("independent"), Type.Literal("dag-propagate")])`
|
- [x] `WorkflowCostOptions.propagationMode` is `Type.Union([Type.Literal("independent"), Type.Literal("dag-propagate")])`
|
||||||
- [ ] Re-exported from `src/schema/index.ts`
|
- [x] Re-exported from `src/schema/index.ts`
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
@@ -35,8 +35,11 @@ Define all analysis function return type schemas in `src/schema/results.ts`. The
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
> To be filled by implementation agent
|
All schemas follow the TypeBox-as-single-source-of-truth pattern. WorkflowCostTaskEntry is an internal schema (not exported) used within WorkflowCostResult's tasks array. EvConfig fields use `Type.Number({ default: 0 })` per architecture spec for defaults. The `WorkflowCostOptions.propagationMode` is correctly a `Type.Union` of two `Type.Literal` values as specified. Results.js was already re-exported from index.ts.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
> To be filled on completion
|
Implemented all 7 analysis result TypeBox schemas with `Static<typeof>` type aliases.
|
||||||
|
- Created: `src/schema/results.ts` (7 schema constants + 7 type aliases + 1 internal WorkflowCostTaskEntry)
|
||||||
|
- Modified: `test/schema.test.ts` (46 new tests: 39 runtime validation + 7 compile-time type alias verification)
|
||||||
|
- Tests: 137 total, all passing; `tsc --noEmit` clean
|
||||||
@@ -183,3 +183,294 @@ type TaskImpact = import('../src/schema/enums.js').TaskImpact;
|
|||||||
type TaskLevel = import('../src/schema/enums.js').TaskLevel;
|
type TaskLevel = import('../src/schema/enums.js').TaskLevel;
|
||||||
type TaskPriority = import('../src/schema/enums.js').TaskPriority;
|
type TaskPriority = import('../src/schema/enums.js').TaskPriority;
|
||||||
type TaskStatus = import('../src/schema/enums.js').TaskStatus;
|
type TaskStatus = import('../src/schema/enums.js').TaskStatus;
|
||||||
|
|
||||||
|
// --- Result schema tests ---
|
||||||
|
|
||||||
|
import {
|
||||||
|
RiskPathResult as RiskPathResultSchema,
|
||||||
|
DecomposeResult as DecomposeResultSchema,
|
||||||
|
WorkflowCostOptions as WorkflowCostOptionsSchema,
|
||||||
|
WorkflowCostResult as WorkflowCostResultSchema,
|
||||||
|
EvConfig as EvConfigSchema,
|
||||||
|
EvResult as EvResultSchema,
|
||||||
|
RiskDistributionResult as RiskDistributionResultSchema,
|
||||||
|
} from '../src/schema/results.js';
|
||||||
|
|
||||||
|
// Re-import type aliases for compile-time verification
|
||||||
|
type RiskPathResultType = import('../src/schema/results.js').RiskPathResult;
|
||||||
|
type DecomposeResultType = import('../src/schema/results.js').DecomposeResult;
|
||||||
|
type WorkflowCostOptionsType = import('../src/schema/results.js').WorkflowCostOptions;
|
||||||
|
type WorkflowCostResultType = import('../src/schema/results.js').WorkflowCostResult;
|
||||||
|
type EvConfigType = import('../src/schema/results.js').EvConfig;
|
||||||
|
type EvResultType = import('../src/schema/results.js').EvResult;
|
||||||
|
type RiskDistributionResultType = import('../src/schema/results.js').RiskDistributionResult;
|
||||||
|
|
||||||
|
describe('RiskPathResult schema', () => {
|
||||||
|
it('accepts valid input', () => {
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { path: ['a', 'b', 'c'], totalRisk: 0.75 })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts empty path', () => {
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { path: [], totalRisk: 0 })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects missing fields', () => {
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { path: ['a'] })).toBe(false);
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { totalRisk: 0.5 })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong types', () => {
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { path: 'not-array', totalRisk: 0.5 })).toBe(false);
|
||||||
|
expect(Value.Check(RiskPathResultSchema, { path: ['a'], totalRisk: 'not-number' })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DecomposeResult schema', () => {
|
||||||
|
it('accepts shouldDecompose=true with reasons', () => {
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { shouldDecompose: true, reasons: ['high risk', 'broad scope'] })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts shouldDecompose=false with empty reasons', () => {
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { shouldDecompose: false, reasons: [] })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects missing fields', () => {
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { shouldDecompose: true })).toBe(false);
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { reasons: ['x'] })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong types', () => {
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { shouldDecompose: 'yes', reasons: [] })).toBe(false);
|
||||||
|
expect(Value.Check(DecomposeResultSchema, { shouldDecompose: true, reasons: 'not-array' })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('WorkflowCostOptions schema', () => {
|
||||||
|
it('accepts empty object (all fields optional)', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, {})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts all fields specified', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, {
|
||||||
|
includeCompleted: true,
|
||||||
|
limit: 10,
|
||||||
|
propagationMode: 'independent',
|
||||||
|
defaultQualityRetention: 0.9,
|
||||||
|
})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts dag-propagate propagationMode', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, { propagationMode: 'dag-propagate' })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects invalid propagationMode', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, { propagationMode: 'invalid' })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong type for boolean field', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, { includeCompleted: 'yes' })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong type for number fields', () => {
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, { limit: 'ten' })).toBe(false);
|
||||||
|
expect(Value.Check(WorkflowCostOptionsSchema, { defaultQualityRetention: 'high' })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('WorkflowCostResult schema', () => {
|
||||||
|
const validResult = {
|
||||||
|
tasks: [{
|
||||||
|
taskId: 'task-1',
|
||||||
|
name: 'My Task',
|
||||||
|
ev: 3.5,
|
||||||
|
pIntrinsic: 0.8,
|
||||||
|
pEffective: 0.75,
|
||||||
|
probability: 0.75,
|
||||||
|
scopeCost: 2.0,
|
||||||
|
impactWeight: 1.5,
|
||||||
|
}],
|
||||||
|
totalEv: 3.5,
|
||||||
|
averageEv: 3.5,
|
||||||
|
propagationMode: 'independent',
|
||||||
|
};
|
||||||
|
|
||||||
|
it('accepts valid result with independent mode', () => {
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, validResult)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid result with dag-propagate mode', () => {
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, { ...validResult, propagationMode: 'dag-propagate' })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts empty tasks array', () => {
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, {
|
||||||
|
tasks: [],
|
||||||
|
totalEv: 0,
|
||||||
|
averageEv: 0,
|
||||||
|
propagationMode: 'independent',
|
||||||
|
})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects missing fields', () => {
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, { tasks: [], totalEv: 0, averageEv: 0 })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects invalid propagationMode', () => {
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, { ...validResult, propagationMode: 'invalid' })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects task entry with missing fields', () => {
|
||||||
|
const incomplete = {
|
||||||
|
tasks: [{ taskId: 't1', name: 'T1' }],
|
||||||
|
totalEv: 0,
|
||||||
|
averageEv: 0,
|
||||||
|
propagationMode: 'independent',
|
||||||
|
};
|
||||||
|
expect(Value.Check(WorkflowCostResultSchema, incomplete)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('EvConfig schema', () => {
|
||||||
|
it('accepts empty object (all fields optional)', () => {
|
||||||
|
expect(Value.Check(EvConfigSchema, {})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts all fields specified', () => {
|
||||||
|
expect(Value.Check(EvConfigSchema, {
|
||||||
|
retries: 3,
|
||||||
|
fallbackCost: 10,
|
||||||
|
timeLost: 5,
|
||||||
|
valueRate: 0.5,
|
||||||
|
})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong types', () => {
|
||||||
|
expect(Value.Check(EvConfigSchema, { retries: 'three' })).toBe(false);
|
||||||
|
expect(Value.Check(EvConfigSchema, { fallbackCost: true })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects unknown properties (additionalProperties)', () => {
|
||||||
|
// TypeBox Object by default allows additional properties through Check
|
||||||
|
// This test documents behavior — strict additionalProperties would need Type.Object({...}, { additionalProperties: false })
|
||||||
|
expect(Value.Check(EvConfigSchema, { unknownField: 42 })).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('EvResult schema', () => {
|
||||||
|
it('accepts valid input', () => {
|
||||||
|
expect(Value.Check(EvResultSchema, { ev: 3.5, pSuccess: 0.8, expectedRetries: 1.2 })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects missing fields', () => {
|
||||||
|
expect(Value.Check(EvResultSchema, { ev: 3.5, pSuccess: 0.8 })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects wrong types', () => {
|
||||||
|
expect(Value.Check(EvResultSchema, { ev: 'high', pSuccess: 0.8, expectedRetries: 1 })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RiskDistributionResult schema', () => {
|
||||||
|
it('accepts valid distribution', () => {
|
||||||
|
expect(Value.Check(RiskDistributionResultSchema, {
|
||||||
|
trivial: ['t1'],
|
||||||
|
low: ['t2', 't3'],
|
||||||
|
medium: [],
|
||||||
|
high: ['t4'],
|
||||||
|
critical: [],
|
||||||
|
unspecified: ['t5'],
|
||||||
|
})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts all empty arrays', () => {
|
||||||
|
expect(Value.Check(RiskDistributionResultSchema, {
|
||||||
|
trivial: [],
|
||||||
|
low: [],
|
||||||
|
medium: [],
|
||||||
|
high: [],
|
||||||
|
critical: [],
|
||||||
|
unspecified: [],
|
||||||
|
})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects missing fields', () => {
|
||||||
|
expect(Value.Check(RiskDistributionResultSchema, {
|
||||||
|
trivial: [],
|
||||||
|
low: [],
|
||||||
|
medium: [],
|
||||||
|
high: [],
|
||||||
|
critical: [],
|
||||||
|
})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects non-array values', () => {
|
||||||
|
expect(Value.Check(RiskDistributionResultSchema, {
|
||||||
|
trivial: 't1',
|
||||||
|
low: [],
|
||||||
|
medium: [],
|
||||||
|
high: [],
|
||||||
|
critical: [],
|
||||||
|
unspecified: [],
|
||||||
|
})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects non-string array elements', () => {
|
||||||
|
expect(Value.Check(RiskDistributionResultSchema, {
|
||||||
|
trivial: [123],
|
||||||
|
low: [],
|
||||||
|
medium: [],
|
||||||
|
high: [],
|
||||||
|
critical: [],
|
||||||
|
unspecified: [],
|
||||||
|
})).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Result type alias correctness (compile-time)', () => {
|
||||||
|
it('RiskPathResult type accepts valid values', () => {
|
||||||
|
const result: RiskPathResultType = { path: ['a'], totalRisk: 0.5 };
|
||||||
|
expect(result.totalRisk).toBe(0.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('DecomposeResult type accepts valid values', () => {
|
||||||
|
const result: DecomposeResultType = { shouldDecompose: true, reasons: ['high risk'] };
|
||||||
|
expect(result.shouldDecompose).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('WorkflowCostOptions type accepts valid values', () => {
|
||||||
|
const opts: WorkflowCostOptionsType = { propagationMode: 'dag-propagate', limit: 5 };
|
||||||
|
expect(opts.propagationMode).toBe('dag-propagate');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('WorkflowCostResult type accepts valid values', () => {
|
||||||
|
const result: WorkflowCostResultType = {
|
||||||
|
tasks: [],
|
||||||
|
totalEv: 0,
|
||||||
|
averageEv: 0,
|
||||||
|
propagationMode: 'independent',
|
||||||
|
};
|
||||||
|
expect(result.propagationMode).toBe('independent');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('EvConfig type accepts valid values', () => {
|
||||||
|
const config: EvConfigType = { retries: 3, fallbackCost: 10 };
|
||||||
|
expect(config.retries).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('EvResult type accepts valid values', () => {
|
||||||
|
const result: EvResultType = { ev: 2.5, pSuccess: 0.9, expectedRetries: 0.5 };
|
||||||
|
expect(result.ev).toBe(2.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('RiskDistributionResult type accepts valid values', () => {
|
||||||
|
const result: RiskDistributionResultType = {
|
||||||
|
trivial: [],
|
||||||
|
low: [],
|
||||||
|
medium: [],
|
||||||
|
high: [],
|
||||||
|
critical: [],
|
||||||
|
unspecified: [],
|
||||||
|
};
|
||||||
|
expect(result.unspecified).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user