Multipoint
This commit is contained in:
215
test/assignMarkerId.test.js
Normal file
215
test/assignMarkerId.test.js
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* 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); }
|
||||
});
|
||||
});
|
||||
25
test/fixtures/runAssignMarkerId.mjs
vendored
Normal file
25
test/fixtures/runAssignMarkerId.mjs
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Dünner Runner für assignMarkerId – wird von assignMarkerId.test.js per spawnSync aufgerufen.
|
||||
*
|
||||
* Argumente:
|
||||
* node runAssignMarkerId.mjs <robotPath> <paramsJson>
|
||||
*
|
||||
* Gibt das Ergebnis als JSON-Zeile auf stdout aus.
|
||||
* Wirft der Aufruf, erscheint { __error: "<message>" } + Exit 1.
|
||||
*/
|
||||
import { assignMarkerId } from '../../server/editRobot.js';
|
||||
|
||||
const [, , robotPath, paramsJson] = process.argv;
|
||||
if (!robotPath || !paramsJson) {
|
||||
process.stderr.write('Usage: runAssignMarkerId.mjs <robotPath> <paramsJson>\n');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
try {
|
||||
const params = JSON.parse(paramsJson);
|
||||
const result = await assignMarkerId(robotPath, params);
|
||||
process.stdout.write(JSON.stringify(result) + '\n');
|
||||
} catch (err) {
|
||||
process.stdout.write(JSON.stringify({ __error: err.message }) + '\n');
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user