test-invariants.spec.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { describe, expect, it, vi } from 'vitest'
  2. import { Context, Service } from 'cordis'
  3. import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
  4. import { packageInvariantOwners } from './package-invariants.ts'
  5. import {
  6. MANUAL_INVARIANT_TESTS,
  7. testInvariantCompanionPaths,
  8. testInvariantCompanions,
  9. } from './test-invariants.ts'
  10. declare module 'cordis' {
  11. interface Context {
  12. testInvariantProbe: TestInvariantProbe
  13. }
  14. }
  15. class TestInvariantProbe extends Service {
  16. constructor(ctx: Context) {
  17. super(ctx, 'testInvariantProbe')
  18. }
  19. }
  20. describe('global test invariant host', () => {
  21. it('uses one exhaustive topology to reserve every package name with enabled checks', async () => {
  22. const ctx = new Context()
  23. await ctx.plugin(TestInvariantProbe)
  24. const owners = packageInvariantOwners(process.cwd())
  25. expect(Object.keys(testInvariantCompanions)).toHaveLength(owners.length)
  26. const unreserved: string[] = []
  27. for (const owner of owners) {
  28. try {
  29. const dispose = ctx.invariants.register(owner.packageName, () => {})
  30. unreserved.push(owner.packageName)
  31. dispose()
  32. } catch (error) {
  33. expect(error).toHaveProperty(
  34. 'message',
  35. `invariants: package "${owner.packageName}" is already registered`,
  36. )
  37. }
  38. }
  39. expect(unreserved).toEqual([])
  40. })
  41. it('mounts the owning package companion while leaving non-package roots service-only', () => {
  42. expect(testInvariantCompanionPaths('/repo/packages/core/tools/tests/tools.spec.ts'))
  43. .toEqual(['../packages/core/tools/src/invariant.ts'])
  44. expect(testInvariantCompanionPaths('/repo/examples/echo-agent/tests/echo.spec.ts')).toEqual([])
  45. expect(testInvariantCompanionPaths('/repo/scripts/test-invariants.spec.ts'))
  46. .toEqual(Object.keys(testInvariantCompanions).sort())
  47. })
  48. it('executes each companion registration with its owning package name', async () => {
  49. const owners = new Map(packageInvariantOwners(process.cwd()).map(owner => [owner.sourcePath, owner.packageName]))
  50. const registrations = new Map<string, string>()
  51. const register = vi.fn((_packageName: string, installer: InvariantInstaller) => {
  52. expect(typeof installer).toBe('function')
  53. return () => {}
  54. })
  55. const fakeContext = { invariants: { register } } as unknown as Context
  56. for (const [rawPath, companion] of Object.entries(testInvariantCompanions)) {
  57. const path = rawPath.replace(/^\.\.\//, '')
  58. await companion.apply(fakeContext)
  59. const call = register.mock.calls.at(-1)
  60. if (call === undefined) throw new Error(`${path}: companion did not register`)
  61. registrations.set(path, call[0])
  62. }
  63. expect(registrations).toEqual(owners)
  64. })
  65. it('limits manual composition to focused invariant topology tests', () => {
  66. expect(MANUAL_INVARIANT_TESTS).toEqual([
  67. '/packages/support/invariants/tests/service.spec.ts',
  68. '/packages/core/session/tests/invariant.spec.ts',
  69. '/packages/core/agent/tests/invariant.spec.ts',
  70. '/packages/core/scope/tests/invariant.spec.ts',
  71. '/packages/core/agent-loop/tests/invariant.spec.ts',
  72. '/packages/examples/agent-spine-demo/tests/agent-core.spec.ts',
  73. ])
  74. })
  75. })