// concierge-write.test.js — Test de PORTÉE D'ÉCRITURE (garde-fou du canal HA). // Doit ÉCHOUER si une écriture peut sortir de la constante airtria_vehicle_label. // À faire tourner à CHAQUE modification, pas une seule fois (cf. EVCS advisor). // Pur statique + require : aucun réseau, aucun token, aucune écriture. 'use strict'; const fs = require('fs'); const path = require('path'); const assert = require('assert'); const SRC = path.join(__dirname, 'concierge-write.js'); const src = fs.readFileSync(SRC, 'utf8'); const mod = require('./concierge-write.js'); let ko = 0; const check = (name, fn) => { try { fn(); console.log(` ok ${name}`); } catch (e) { ko++; console.log(` FAIL ${name} : ${e.message}`); } }; console.log('=== Test de portée d\'écriture concierge-write.js ==='); // 1. La constante est exactement l'entité attendue. check('constante = input_text.airtria_vehicle_label', () => assert.strictEqual(mod.HELPER_ENTITY, 'input_text.airtria_vehicle_label')); // 2. entity_id n'est JAMAIS accolé à autre chose que la constante // (pas de littéral d'entité, pas d'interpolation, pas de concaténation). check('entity_id uniquement = HELPER_ENTITY', () => { const occ = [...src.matchAll(/entity_id\s*:\s*([^,}\n]+)/g)].map(m => m[1].trim()); assert(occ.length > 0, 'aucun entity_id trouvé'); for (const v of occ) assert.strictEqual(v, 'HELPER_ENTITY', `entity_id dynamique ou littéral interdit : ${v}`); }); // 3. Aucune autre entité HA en dur (aucun autre "domaine.entite") que la constante. check('aucune entité HA littérale hors la constante', () => { const decl = "'input_text.airtria_vehicle_label'"; const lits = [...src.matchAll(/['"`]([a-z_]+\.[a-z0-9_]+)['"`]/g)].map(m => m[0]); for (const l of lits) assert.strictEqual(l, decl, `littéral d'entité interdit : ${l}`); }); // 4. Un SEUL appel de service, et c'est input_text/set_value (aucun actionneur). check('seul service = input_text/set_value', () => { const services = [...src.matchAll(/\/api\/services\/([a-z_]+\/[a-z_]+)/g)] .map(m => m[1]); assert.deepStrictEqual(services, ['input_text/set_value'], `services inattendus : ${services.join(', ') || '(aucun)'}`); }); // 5. La relecture existe (garde-fou rejet silencieux). check('relecture présente (/api/states/)', () => assert(/\/api\/states\//.test(src), 'pas de relecture après écriture')); console.log(ko === 0 ? '\nTOUT VERT' : `\n${ko} test(s) EN ÉCHEC`); process.exit(ko === 0 ? 0 : 1);