import test from 'node:test';import assert from 'node:assert/strict';import vm from 'node:vm';import {readFileSync} from 'node:fs'; const gateway=readFileSync(new URL('../deploy-admin-functions.mjs',import.meta.url),'utf8'); function harness(rows){const source=gateway.slice(gateway.indexOf('async function appReviewTarget'),gateway.indexOf('function normalizeWordRow'));let queries=[];const ctx={isAdminUser:()=>false,ownLegacyId:u=>u.id,number:v=>Number(v)||0,DEFAULT_COMPANY_ID:'c',fail:(status,message)=>{throw Error(status+': '+message)},Psql:{oneOrNone:async(s,p)=>{queries.push({s,p});return rows;}},appLearningTarget:async()=>{throw Error('No teaching relationship');}};vm.createContext(ctx);vm.runInContext(source,ctx);return{ctx,queries};} const teacher={id:11,get:k=>k==='legacyGroupId'?3:null}; test('接手老师仅凭当前任务获得学员复习筛选和来源词表权限',async()=>{const {ctx,queries}=harness({exists:1});assert.equal(await ctx.appReviewTarget(teacher,20),20);await ctx.authorizeLearningRecordAccess(teacher,{UserID:20,pl:10,GeneralID:100});assert.ok(queries.every(q=>q.p[0]==='c'&&q.p[1]==='11'&&q.p[2]==='20'));assert.equal(queries.at(-1).p[3],'100');}); test('其他学员和未分配来源被拒绝;不自动放宽整段学习历史',async()=>{const {ctx}=harness(null);await assert.rejects(ctx.appReviewTarget(teacher,99),/403/);await assert.rejects(ctx.authorizeLearningRecordAccess(teacher,{UserID:20,pl:10,GeneralID:999}),/No teaching relationship/);});