Files
appRobotHoming/test/assignMarkerId.test.js
2026-06-17 22:57:52 +02:00

216 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* assignMarkerId.test.js
* ======================
* Integration-Test für server/editRobot.js → assignMarkerId().
*
* Testet insbesondere den Guard für fehlende position_mm (Marker ohne
* triangulierte Position, z.B. Einzelkamera-Marker nach Schritt 5).
*
* Technisch: editRobot.js ist ein ES-Modul — es wird über den dünnen Runner
* test/fixtures/runAssignMarkerId.mjs per spawnSync aufgerufen (gleiche
* Strategie wie yAxisRotation.test.js für das Python-Skript).
* Datei-I/O läuft gegen echte Temp-Dateien (os.tmpdir()).
*/
const { spawnSync } = require('child_process');
const os = require('os');
const fs = require('fs');
const path = require('path');
const RUNNER = path.join(__dirname, 'fixtures', 'runAssignMarkerId.mjs');
// ── Hilfsfunktionen ───────────────────────────────────────────────────────────
function callAssignMarkerId(robotPath, params) {
const proc = spawnSync('node', [RUNNER, robotPath, JSON.stringify(params)], {
encoding: 'utf-8',
});
if (proc.error) throw proc.error;
const stdout = (proc.stdout ?? '').trim();
if (!stdout) throw new Error(`Kein Output.\nstderr: ${proc.stderr}`);
return JSON.parse(stdout);
}
function makeTempRobot(content) {
const p = path.join(
os.tmpdir(),
`robot_test_${Date.now()}_${Math.random().toString(36).slice(2)}.json`
);
fs.writeFileSync(p, JSON.stringify(content, null, 2), 'utf8');
return p;
}
const ROBOT_WITH_42 = () => ({
links: {
Arm1: { markers: [{ id: 42, set: 'A0', position: [100, 200, 300] }] },
},
});
const ROBOT_EMPTY = () => ({
links: { Arm1: { markers: [] } },
});
// ── Eingabe-Validierung ───────────────────────────────────────────────────────
describe('assignMarkerId Eingabe-Validierung', () => {
test('ungültige Marker-ID → changed: false', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, { markerId: -1, link: 'Arm1' });
expect(r.changed).toBe(false);
expect(r.error).toMatch(/Ungültige Marker-ID/);
} finally { fs.unlinkSync(p); }
});
test('kein link für neuen Marker → changed: false', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 99,
extraMarkers: [{ marker_id: 99, position_mm: [10, 20, 30] }],
});
expect(r.changed).toBe(false);
expect(r.error).toMatch(/Link/);
} finally { fs.unlinkSync(p); }
});
});
// ── Guard: fehlende position_mm ───────────────────────────────────────────────
describe('assignMarkerId Guard: fehlende position_mm (z.B. Einzelkamera-Marker)', () => {
test('extraMarker ohne position_mm → changed: false, kein Crash', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 55,
link: 'Arm1',
extraMarkers: [{ marker_id: 55 }], // kein position_mm
});
expect(r.changed).toBe(false);
expect(r.error).toMatch(/position_mm fehlt/);
} finally { fs.unlinkSync(p); }
});
test('extraMarker mit position_mm: null → changed: false, kein Crash', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 56,
link: 'Arm1',
extraMarkers: [{ marker_id: 56, position_mm: null }],
});
expect(r.changed).toBe(false);
expect(r.error).toMatch(/position_mm fehlt/);
} finally { fs.unlinkSync(p); }
});
test('extraMarker mit position_mm als String → changed: false, kein Crash', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 57,
link: 'Arm1',
extraMarkers: [{ marker_id: 57, position_mm: '[1,2,3]' }],
});
expect(r.changed).toBe(false);
expect(r.error).toMatch(/position_mm fehlt/);
} finally { fs.unlinkSync(p); }
});
});
// ── Normalfall: Marker hinzufügen ─────────────────────────────────────────────
describe('assignMarkerId Normalfall: neuen Marker hinzufügen', () => {
test('gültige position_mm → changed: true, action: added, Datei geschrieben', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 77,
link: 'Arm1',
extraMarkers: [{ marker_id: 77, position_mm: [10.1, 20.22, 30.333] }],
});
expect(r.changed).toBe(true);
expect(r.change.action).toBe('added');
expect(r.change.markerId).toBe(77);
expect(r.change.newLink).toBe('Arm1');
const saved = JSON.parse(fs.readFileSync(p, 'utf8'));
const added = saved.links.Arm1.markers.find(m => m.id === 77);
expect(added).toBeDefined();
expect(Array.isArray(added.position)).toBe(true);
expect(added.position).toHaveLength(3);
} finally { fs.unlinkSync(p); }
});
test('Marker nicht in extraMarkers → changed: false', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, { markerId: 99, link: 'Arm1', extraMarkers: [] });
expect(r.changed).toBe(false);
expect(r.error).toMatch(/nicht.*vorhanden/i);
} finally { fs.unlinkSync(p); }
});
test('mit set → Marker hat set-Wert in der gespeicherten Datei', () => {
const p = makeTempRobot(ROBOT_EMPTY());
try {
const r = callAssignMarkerId(p, {
markerId: 78,
link: 'Arm1',
set: 'A0',
extraMarkers: [{ marker_id: 78, position_mm: [1, 2, 3] }],
});
expect(r.changed).toBe(true);
const saved = JSON.parse(fs.readFileSync(p, 'utf8'));
const added = saved.links.Arm1.markers.find(m => m.id === 78);
expect(added.set).toBe('A0');
} finally { fs.unlinkSync(p); }
});
});
// ── Normalfall: bestehenden Marker aktualisieren ──────────────────────────────
describe('assignMarkerId Normalfall: bestehenden Marker aktualisieren', () => {
test('Set ändern → changed: true, action: updated, Datei geändert', () => {
const p = makeTempRobot(ROBOT_WITH_42());
try {
const r = callAssignMarkerId(p, { markerId: 42, set: 'B0' });
expect(r.changed).toBe(true);
expect(r.change.action).toBe('updated');
expect(r.change.oldSet).toBe('A0');
expect(r.change.newSet).toBe('B0');
const saved = JSON.parse(fs.readFileSync(p, 'utf8'));
expect(saved.links.Arm1.markers.find(m => m.id === 42).set).toBe('B0');
} finally { fs.unlinkSync(p); }
});
test('in anderen Link verschieben → oldLink / newLink korrekt, Datei geändert', () => {
const p = makeTempRobot(ROBOT_WITH_42());
try {
const r = callAssignMarkerId(p, { markerId: 42, link: 'Arm2' });
expect(r.changed).toBe(true);
expect(r.change.oldLink).toBe('Arm1');
expect(r.change.newLink).toBe('Arm2');
const saved = JSON.parse(fs.readFileSync(p, 'utf8'));
expect(saved.links.Arm1.markers.find(m => m.id === 42)).toBeUndefined();
expect(saved.links.Arm2.markers.find(m => m.id === 42)).toBeDefined();
} finally { fs.unlinkSync(p); }
});
test('bestehender Marker: fehlende position_mm in extraMarkers ist irrelevant', () => {
const p = makeTempRobot(ROBOT_WITH_42());
try {
// Marker 42 ist in robot.json → position_mm-Guard darf nicht zuschlagen
const r = callAssignMarkerId(p, {
markerId: 42,
set: 'C0',
extraMarkers: [{ marker_id: 42 }], // kein position_mm aber irrelevant
});
expect(r.changed).toBe(true);
expect(r.change.action).toBe('updated');
} finally { fs.unlinkSync(p); }
});
});