File size: 5,245 Bytes
ec8acdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';

import {
  PRIORITY_COUNTRIES,
  EXPOSURE_CENTROIDS,
  computeBoundedExposure,
  computeExposure,
  getRadiusForEventType,
  listCountryPopulations,
  MAX_EXPOSURE_RADIUS_KM,
} from '../shared/analysis-population-exposure.ts';
import { getPopulationExposure } from '../server/worldmonitor/displacement/v1/get-population-exposure.ts';
import {
  Z_THRESHOLD_LOW,
  Z_THRESHOLD_MEDIUM,
  Z_THRESHOLD_HIGH,
  getBaselineSeverity,
} from '../shared/analysis-temporal-severity.ts';

describe('analysis-population-exposure core', () => {
  it('keeps the priority table and centroids aligned', () => {
    const countryCodes = Object.keys(PRIORITY_COUNTRIES).sort();
    const centroidCodes = Object.keys(EXPOSURE_CENTROIDS).sort();
    assert.deepEqual(countryCodes, centroidCodes);
    assert.equal(countryCodes.length, 20);
    for (const [code, [lat, lon]] of Object.entries(EXPOSURE_CENTROIDS)) {
      assert.ok(lat >= -90 && lat <= 90, `${code} lat in range`);
      assert.ok(lon >= -180 && lon <= 180, `${code} lon in range`);
    }
  });

  it('picks the nearest centroid and applies density * area', () => {
    // Point right on Israel's centroid.
    const exposure = computeExposure(31.0, 34.8, 50);
    assert.equal(exposure.nearestCountry, 'ISR');
    const density = PRIORITY_COUNTRIES.ISR.pop / PRIORITY_COUNTRIES.ISR.area;
    assert.equal(exposure.densityPerKm2, Math.round(density));
    assert.equal(exposure.exposedPopulation, Math.round(density * Math.PI * 50 * 50));
    assert.equal(exposure.exposureRadiusKm, 50);
  });

  it('resolves interior points, not just exact centroids', () => {
    // Kyiv is nearer the Ukraine centroid than any other.
    const exposure = computeExposure(50.45, 30.52, 100);
    assert.equal(exposure.nearestCountry, 'UKR');
  });

  it('maps event types to radii with a 50km default', () => {
    assert.equal(getRadiusForEventType('earthquake'), 100);
    assert.equal(getRadiusForEventType('flood'), 100);
    assert.equal(getRadiusForEventType('wildfire'), 30);
    assert.equal(getRadiusForEventType('fire'), 30);
    assert.equal(getRadiusForEventType('battle'), 50);
    assert.equal(getRadiusForEventType('state-based'), 50);
    assert.equal(getRadiusForEventType('unknown-thing'), 50);
  });

  it('lists country populations with rounded densities', () => {
    const countries = listCountryPopulations();
    assert.equal(countries.length, 20);
    const india = countries.find((c) => c.code === 'IND');
    assert.ok(india);
    assert.equal(india.population, PRIORITY_COUNTRIES.IND.pop);
    assert.equal(
      india.densityPerKm2,
      Math.round(PRIORITY_COUNTRIES.IND.pop / PRIORITY_COUNTRIES.IND.area),
    );
  });
});

describe('analysis-temporal-severity core', () => {
  it('exports the canonical z-score thresholds', () => {
    assert.equal(Z_THRESHOLD_LOW, 1.5);
    assert.equal(Z_THRESHOLD_MEDIUM, 2.0);
    assert.equal(Z_THRESHOLD_HIGH, 3.0);
  });

  it('classifies severity bands exactly at the boundaries', () => {
    assert.equal(getBaselineSeverity(3.0), 'critical');
    assert.equal(getBaselineSeverity(4.7), 'critical');
    assert.equal(getBaselineSeverity(2.999), 'high');
    assert.equal(getBaselineSeverity(2.0), 'high');
    assert.equal(getBaselineSeverity(1.999), 'medium');
    assert.equal(getBaselineSeverity(1.5), 'medium');
    assert.equal(getBaselineSeverity(1.499), 'normal');
    assert.equal(getBaselineSeverity(0), 'normal');
  });
});

describe('exposure radius clamping', () => {
  it('caps free-form agent radii so an absurd request cannot return an absurd population', () => {
    // Unclamped, radius 20000 returned ~5.6e11 people — roughly 69x the world
    // population — because density is multiplied across the whole disc.
    const wild = computeBoundedExposure(31.0, 34.8, 20000);
    assert.equal(wild.exposureRadiusKm, MAX_EXPOSURE_RADIUS_KM, 'result reports the radius actually used');
    const capped = computeExposure(31.0, 34.8, MAX_EXPOSURE_RADIUS_KM);
    assert.equal(wild.exposedPopulation, capped.exposedPopulation);
    assert.ok(wild.exposedPopulation < 8.1e9 * 10, 'stays within an order of magnitude of world population');
  });

  it('leaves in-range radii untouched', () => {
    for (const r of [1, 30, 50, 100, MAX_EXPOSURE_RADIUS_KM]) {
      assert.equal(computeExposure(31.0, 34.8, r).exposureRadiusKm, r);
    }
  });

  it('treats non-finite and negative radii as zero rather than NaN', () => {
    for (const bad of [Number.NaN, Number.POSITIVE_INFINITY, -5]) {
      const result = computeBoundedExposure(31.0, 34.8, bad);
      assert.equal(result.exposedPopulation, 0);
      assert.equal(result.exposureRadiusKm, 0);
    }
  });
});

describe('v1 population-exposure compatibility', () => {
  it('preserves the existing unbounded REST radius contract', async () => {
    const radius = MAX_EXPOSURE_RADIUS_KM + 1;
    const result = await getPopulationExposure(
      /** @type {never} */ ({}),
      { mode: 'exposure', lat: 31.0, lon: 34.8, radius },
    );

    assert.equal(result.exposure?.exposureRadiusKm, radius);
    assert.deepEqual(result.exposure, computeExposure(31.0, 34.8, radius));
  });
});