import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' const read = (relativeUrl) => readFileSync(new URL(relativeUrl, import.meta.url), 'utf8') const controller = read('../../firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformInboundMeasurementController.java') const service = read('../../firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java') const warehouseClient = read('../../firstleg/src/main/java/com/baiyue/firstleg/client/WarehousePalletLocationClient.java') const serviceTests = read('../../firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java') const openapi = read('../../firstleg/src/main/resources/openapi/firstleg-v1.yaml') const adminApi = read('../../../apps/admin-web/src/modules/inbounds/weight/api/weightOcr.ts') const adminPanel = read('../../../apps/admin-web/src/modules/inbounds/weight/components/WeightOcrPanel.vue') const adminBehavior = read('../../../apps/admin-web/src/modules/inbounds/weight/components/WeightOcrPanel.behavior.test.ts') function endpointBlock(source, marker, nextMarker) { const start = source.indexOf(marker) assert.notEqual(start, -1, `missing contract marker: ${marker}`) const end = source.indexOf(nextMarker, start + marker.length) return source.slice(start, end === -1 ? source.length : end) } test('backend Controller exposes a keyword-filtered bounded page instead of an unbounded array', () => { const block = endpointBlock(controller, '@GetMapping("/weight-pallet-options")', '@BusinessAudit') assert.match(block, /ApiResponse>/) assert.doesNotMatch(block, /ApiResponse>/) assert.match(block, /\bpage\b/) assert.match(block, /\bsize\b/) assert.match(block, /\bkeyword\b/) const boundedSize = [...block.matchAll(/@Max\((\d+)\)/g)].map((match) => Number(match[1])) assert.ok(boundedSize.some((maximum) => maximum > 0 && maximum <= 200), 'size must have a finite Controller maximum no greater than 200') }) test('Firstleg forwards the bound to Warehouse instead of loading the full warehouse and slicing in memory', () => { const clientBlock = endpointBlock(warehouseClient, '@GetMapping("/pallets/snapshots")', '@PostMapping') assert.match(clientBlock, /ApiResponse>/) assert.doesNotMatch(clientBlock, /ApiResponse>/) for (const parameter of ['page', 'size', 'keyword']) assert.match(clientBlock, new RegExp(`"${parameter}"`)) const serviceBlock = endpointBlock(service, 'public PageResult weightPalletOptions(', '@Transactional') assert.match(serviceBlock, /loadPalletSnapshotPage\(inbound, page, size, keyword\)/) assert.match(service, /palletSnapshots\([\s\S]{0,300}?page[\s\S]{0,80}?size[\s\S]{0,80}?keyword/) assert.doesNotMatch(serviceBlock, /\.stream\(\)[\s\S]*?\.skip\(/) }) test('OpenAPI publishes page, size, keyword and a finite maximum without an array data contract', () => { const block = endpointBlock(openapi, ' /api/platform/v1/first-leg/inbounds/{inboundId}/weight-pallet-options:', ' /api/platform/v1/first-leg/inbounds/{inboundId}/weight-results:') for (const parameter of ['page', 'size', 'keyword']) { assert.match(block, new RegExp(`name: ${parameter}`)) } const maxima = [...block.matchAll(/maximum:\s*(\d+)/g)].map((match) => Number(match[1])) assert.ok(maxima.some((maximum) => maximum > 0 && maximum <= 200), 'OpenAPI size parameter must declare a finite maximum no greater than 200') const dataLine = block.match(/data:\s*\{[^\n]+/)?.[0] || '' assert.doesNotMatch(dataLine, /type:\s*array/) assert.match(block, /(?:records|WeightPalletOptionPage|PageResult)/) }) test('Admin API requests a bounded remote-search page and does not type the response as an array', () => { const block = endpointBlock(adminApi, 'export async function getWeightPalletOptions', 'export async function uploadWeightImage') assert.match(block, /\bpage\b/) assert.match(block, /\bsize\b/) assert.match(block, /\bkeyword\b/) assert.doesNotMatch(block, /ApiEnvelope/) assert.match(block, /(?:records|PageResult|PageResource|PageResponse)/) }) test('Admin skips candidates without weight edit permission or an editable inbound state', () => { const loader = endpointBlock(adminPanel, 'async function loadPalletOptions', 'function chooseFile') const gate = endpointBlock(adminPanel, 'const canLoadPalletOptions', 'const virtualPalletOptions') assert.match(gate, /canEdit\.value/) assert.match(gate, /editable\.value/) assert.match(loader, /!canLoadPalletOptions\.value/) }) test('Admin behavior tests prove both permission and inbound-state request suppression', () => { const cases = [...adminBehavior.matchAll(/it\((['"`])([\s\S]*?)\1,\s*async\s*\(\)\s*=>\s*\{([\s\S]*?)\n\s*\}\)/g)] const suppressionCases = cases.filter(([, , title, body]) => /getWeightPalletOptions/.test(body) && /not\.toHaveBeenCalled/.test(body)) assert.ok(suppressionCases.some(([, , title]) => /edit|permission|权限/i.test(title)), 'missing behavior case: no weight:edit must not request pallet candidates') assert.ok(suppressionCases.some(([, , title]) => /status|editable|状态/i.test(title)), 'missing behavior case: non-editable inbound status must not request pallet candidates') }) test('Admin remote search is bounded and never accumulates every candidate', () => { assert.match(adminPanel, /\bremote\b/) assert.match(adminPanel, /:remote-method=/) const sizes = [...adminPanel.matchAll(/(?:PALLET|pallet).{0,40}(?:PAGE_SIZE|pageSize)\s*=\s*(\d+)/g)] .map((match) => Number(match[1])) assert.ok(sizes.some((size) => size > 0 && size <= 200), 'Admin remote search page size must be finite and no greater than 200') assert.doesNotMatch(adminPanel, /palletOptions\.value\.(?:push|unshift)\s*\(/) assert.doesNotMatch(adminPanel, /palletOptions\.value\s*=\s*\[\s*\.\.\.palletOptions\.value/) assert.match(adminBehavior, /(?:remote search|远程搜索|keyword).{0,220}(?:size|page)/is) }) test('Admin uses a virtualized selector so a large response cannot create one DOM option per candidate', () => { assert.match(adminPanel, / { const cards = endpointBlock(adminPanel, '
') assert.match(cards, /row\.palletCode/) assert.match(cards, /row\.palletType/) assert.match(cards, /row\.palletTareWeightKg/) assert.match(adminBehavior, /(?:historical|history|历史|失去候选|no longer eligible).{0,220}(?:palletCode|托盘编码|TP-)/is) }) test('backend detail reads the stored historical pallet snapshot without revalidating current eligibility', () => { assert.match(serviceTests, /detailUsesStoredPalletSnapshotAfterCandidateBecomesUnavailable/) assert.match(serviceTests, /verify\(warehousePallets, never\(\)\)\.palletSnapshot/) assert.match(serviceTests, /verify\(warehousePallets, never\(\)\)\.palletSnapshots/) }) test('backend evidence fails closed for Warehouse non-2xx and network errors', () => { assert.match(serviceTests, /weightPalletOptionsFailsClosedOnWarehouseNon2xxResponse/) assert.match(serviceTests, /weightPalletOptionsFailsClosedOnWarehouseNetworkError/) assert.match(serviceTests, /FeignException/) assert.match(serviceTests, /RetryableException/) })