const test = require("node:test"); const assert = require("node:assert/strict"); const workflow = require("../../Web/named-manual-restore-workflow.js"); const manualLists = require("../../Web/manual-lists-workflow.js"); const manualFinancial = require("../../Web/manual-financial-workflow.js"); function raw(overrides = {}) { return { itemIndex: 0, enabled: true, groupCode: "INDIVIDUAL", subject: "INDEX", graphicType: "MANUAL_NET_SELL", subtype: "MANUAL_NET_SELL", dataCode: "", ...overrides }; } const options = { id: "db-invalid-00000001-0", fadeDuration: 6 }; const rows = Array.from({ length: 5 }, (_, index) => ({ leftName: `L${index}`, leftAmount: `${index}`, rightName: `R${index}`, rightAmount: `${index + 10}` })); test("s5025 raw restoration accepts only canonical or exact legacy audience signatures", () => { const canonical = workflow.classify(raw(), options); assert.equal(canonical.kind, "net-sell"); assert.equal(canonical.audience, "INDIVIDUAL"); const legacy = workflow.classify(raw({ groupCode: "외국인 순매도 상위(수동)", subject: "", graphicType: "순매도 상위", subtype: "순매도 상위" }), options); assert.equal(legacy.audience, "FOREIGN"); assert.equal(legacy.historical, true); assert.equal(workflow.classify(raw({ groupCode: "외국인 순매도 상위", subject: "", graphicType: "순매도 상위", subtype: "순매도 상위" }), options), null); assert.equal(workflow.classify(raw({ dataCode: "path.dat" }), options), null); }); test("s5025 becomes playable only after one correlated trusted five-row read", () => { const pending = workflow.classify(raw({ enabled: false }), options); const request = workflow.createManualListReadRequest("named-net-read", pending); const entry = workflow.materializeManualList(pending, { requestId: "named-net-read", audience: "INDIVIDUAL", rows }, request); assert.ok(entry); assert.equal(entry.enabled, false); assert.equal(entry.builderKey, "s5025"); assert.equal(manualLists.restorePlaylistEntry(entry).operator.audience, "INDIVIDUAL"); assert.equal(workflow.materializeManualList(pending, { requestId: "stale-read", audience: "INDIVIDUAL", rows }, request), null); }); test("versioned and historical VI raw rows require the current exact native snapshot", () => { const version = "a".repeat(64); const current = workflow.classify(raw({ groupCode: "PAGED_VI", subject: manualLists.viSnapshotSubject, graphicType: "INPUT_ORDER", subtype: "CURRENT", dataCode: version }), options); const request = workflow.createManualListReadRequest("named-vi-read", current); const payload = { requestId: "named-vi-read", itemCount: 2, pageCount: 1, items: [{ code: "005930", name: "삼성전자" }, { code: "000660", name: "SK하이닉스" }], version }; assert.equal(workflow.materializeManualList(current, payload, request).builderKey, "s5074"); assert.equal(workflow.materializeManualList(current, { ...payload, version: "b".repeat(64) }, request), null); const historical = workflow.classify(raw({ groupCode: "", subject: "삼성전자,SK하이닉스", graphicType: "5단 표그래프", subtype: "VI 발동(수동)", dataCode: "" }), options); const historicalRequest = workflow.createManualListReadRequest("named-vi-history", historical); assert.ok(workflow.materializeManualList(historical, { ...payload, requestId: "named-vi-history" }, historicalRequest)); assert.equal(workflow.materializeManualList(historical, { ...payload, requestId: "named-vi-history", items: [...payload.items].reverse() }, historicalRequest), null); assert.equal(workflow.classify(raw({ groupCode: "", subject: "삼성전자,삼성전자", graphicType: "5단 표그래프", subtype: "VI 발동(수동)" }), options), null); assert.equal(workflow.classify(raw({ groupCode: "", subject: "삼성전자, SK하이닉스", graphicType: "5단 표그래프", subtype: "VI 발동(수동)" }), options), null); }); test("GraphE raw rows yield only a fresh-load descriptor with exact screen, market and name", () => { for (const profile of manualFinancial.sourceContract.screens) { const pending = workflow.classify(raw({ groupCode: "코스피", subject: "삼성전자", graphicType: profile.label, subtype: "", dataCode: "" }), options); assert.equal(pending.kind, "financial"); assert.equal(pending.screen, profile.screen); assert.equal(pending.builderKey, profile.builderKey); assert.equal(pending.market, "kospi"); assert.deepEqual(pending.identity, { screen: profile.screen, stockName: "삼성전자" }); } const profile = manualFinancial.sourceContract.screens[0]; assert.equal(workflow.classify(raw({ groupCode: "UNKNOWN", subject: "삼성전자", graphicType: profile.graphicType, subtype: "", dataCode: "" }), options), null); assert.equal(workflow.classify(raw({ groupCode: "KOSPI", subject: "삼성전자", graphicType: profile.graphicType, subtype: "", dataCode: "005930" }), options), null); });