NODEDC_DESIGN_GUIDELINE/server/map-subject-detail-profile....

77 lines
3.5 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import { normalizeMapSubjectDetailProfile, normalizeMapSubjectDetailProfiles } from "./map-subject-detail-profile.mjs";
const registry = JSON.parse(await readFile(new URL("../registry/map-subject-detail-profiles.json", import.meta.url), "utf8"));
test("canonical subject detail profiles are provider-neutral and valid", () => {
const profiles = normalizeMapSubjectDetailProfiles(registry.profiles);
assert.equal(profiles.length, 1);
assert.equal(profiles[0].id, "map.subject-detail.operational.default");
assert.deepEqual(profiles[0].tabs.map((tab) => tab.id), [
"overview", "position", "telemetry", "counters", "equipment", "settings", "maintenance", "diagnostics",
]);
});
test("dynamic sensor readings are fail-closed until ids are explicitly classified", () => {
const profile = normalizeMapSubjectDetailProfile(registry.profiles[0]);
const field = profile.tabs.find((tab) => tab.id === "telemetry").sections[0].fields[0];
assert.equal(field.format, "telemetry_readings");
assert.deepEqual(field.allowedReadingIds, []);
});
test("restricted fields and reading ids cannot be introduced through MCP profiles", () => {
const restrictedField = structuredClone(registry.profiles[0]);
restrictedField.tabs[0].sections[0].fields[0].field = "api_key";
assert.throws(() => normalizeMapSubjectDetailProfile(restrictedField), /map_subject_detail_profile_secret_field/);
const restrictedReading = structuredClone(registry.profiles[0]);
restrictedReading.tabs.find((tab) => tab.id === "telemetry").sections[0].fields[0].allowedReadingIds = ["sensor.imei"];
assert.throws(() => normalizeMapSubjectDetailProfile(restrictedReading), /map_subject_detail_profile_restricted_reading_id/);
});
test("restricted identifiers require an explicit restricted presentation class", () => {
const profile = structuredClone(registry.profiles[0]);
const field = profile.tabs[0].sections[0].fields[0];
field.field = "device_phone_primary";
field.label = "Телефон 1";
assert.throws(
() => normalizeMapSubjectDetailProfile(profile),
/map_subject_detail_profile_restricted_field/,
);
field.dataClass = "restricted";
assert.equal(
normalizeMapSubjectDetailProfile(profile).tabs[0].sections[0].fields[0].dataClass,
"restricted",
);
});
test("string list fields are provider-neutral attribute presentations", () => {
const profile = structuredClone(registry.profiles[0]);
const field = profile.tabs[0].sections[0].fields[0];
field.field = "custom_fields";
field.label = "Пользовательские поля";
field.format = "string_list";
assert.equal(
normalizeMapSubjectDetailProfile(profile).tabs[0].sections[0].fields[0].format,
"string_list",
);
field.source = "fact";
field.field = "sourceId";
assert.throws(
() => normalizeMapSubjectDetailProfile(profile),
/map_subject_detail_profile_string_list_source_invalid/,
);
});
test("profiles reject unknown schema fields and duplicate presentation ids", () => {
const unknown = structuredClone(registry.profiles[0]);
unknown.provider = "gelios";
assert.throws(() => normalizeMapSubjectDetailProfile(unknown), /invalid_map_subject_detail_profile_fields/);
const duplicate = structuredClone(registry.profiles[0]);
duplicate.tabs[1].sections[0].fields[0].id = duplicate.tabs[0].sections[0].fields[0].id;
assert.throws(() => normalizeMapSubjectDetailProfile(duplicate), /duplicate_map_subject_detail_profile_field_id/);
});