'use strict'; const assert = require('node:assert/strict'); const SS = require('../js/skin-score'), UI = require('../js/report-ui'); function sample(score) { const r = structuredClone(SS.MOCK_RESULT); r.score_info.wrinkle_score = score; r.left_mouth_wrinkle_info = { wrinkle_score:100, wrinkle_severity_level:3 }; return r; } for (const p of [0, 23, 65, 80, 95, 100]) { const r=sample(p), bytes=JSON.stringify(r), vm=SS.buildViewModel(r,SS.MOCK_SIDE,{}); assert.equal(vm.cats.wrinkles.P,p,'overall score used directly'); assert.equal(vm.cats.wrinkles.S,Math.round((7+3*p/100+1e-9)*100)/100); assert.equal(vm.dims.firm.P,Math.min(vm.cats.contour.P,p)); assert.equal(vm.wrinkleScoreRule,'api-overall-v1'); assert.equal(vm.cats.wrinkles.vars.overall_wrinkle_score,p); assert.equal(JSON.stringify(r),bytes,'raw data not mutated'); } for (const score of [null, undefined, NaN, Infinity, -1, 101]) { const r=sample(score);const vm=SS.buildViewModel(r,SS.MOCK_SIDE,{}); assert.equal(vm.cats.wrinkles.P,null,'no silent worst-region fallback'); } const onlyOverall={ score_info:{ wrinkle_score:65 } }; assert.equal(SS.buildViewModel(onlyOverall,null,{}).cats.wrinkles.S,8.95,'regions not required'); assert.equal(SS.buildViewModel({wrinkle_score:{value:65}},null,{}).cats.wrinkles.P,65,'legacy scalar field alias'); const base=SS.buildViewModel(sample(65),SS.MOCK_SIDE,{}); const changed=sample(65);changed.left_mouth_wrinkle_info={wrinkle_score:0,wrinkle_severity_level:0}; assert.equal(SS.buildViewModel(changed,SS.MOCK_SIDE,{}).cats.wrinkles.P,base.cats.wrinkles.P,'region severity has no scoring effect'); assert.equal(UI.dimensionScore(8.95),'9.0');assert.equal(UI.dimensionScore(9.45),'9.5'); assert.equal(UI.dimensionScore(9.97),'9.9');assert.equal(UI.dimensionScore(null),'-'); console.log('PASS overall wrinkles: direct 0..100, no inversion/region caps, missing/invalid data, firm min, source immutability, half-up dimension display');