/** * kma-grid.test.ts * * 좌표 → 기상청 격자(nx, ny) 변환. * * 2026-08-16에 이 함수가 nx·ny를 나란히 한 칸씩 밀어서 조회하고 있었다는 걸 발견했다. * 기상청 공식 변환식의 마지막 항은 반올림용 +0.5인데 코드엔 +1.5가 들어 있었다. * 격자 1칸이 5km라 대각선으로 ~7km 떨어진 셀을 읽고 있었고, 같은 서울을 이름("서울")과 * 좌표("37.5665,126.978")로 조회했을 때 오늘 누적 강수량이 9.8mm vs 29mm로 갈리면서 드러났다. * * 이름이 KMA_GRID 표에 있는 도시는 표를 타므로 멀쩡했고, 좌표로 들어온 위치만 틀렸다. * 그래서 몇 년 동안 아무도 못 봤다 — 아래 기대값은 그 표의 값이고, 변환식이 같은 답을 * 내는지 대조하는 게 이 테스트의 요지다. */ import { test, describe } from 'node:test'; import assert from 'node:assert/strict'; import { latLonToKmaGrid } from '../src/tools/weather'; describe('latLonToKmaGrid — 좌표에서 기상청 격자 좌표', () => { // 기대값은 기상청이 배포하는 "동네예보 격자" 표의 값(= 코드 내 KMA_GRID 표와 동일). const cases: Array<[string, number, number, number, number]> = [ ['서울', 37.5665, 126.9780, 60, 127], ['부산', 35.1796, 129.0756, 98, 76], ['대전', 36.3504, 127.3845, 67, 100], ['구미', 36.1195, 128.3446, 84, 96], ]; for (const [name, lat, lon, nx, ny] of cases) { test(`${name} (${lat}, ${lon}) → ${nx}, ${ny}`, () => { assert.deepEqual(latLonToKmaGrid(lat, lon), { nx, ny }); }); } test('+1 밀림 회귀 방어: 서울이 61,128로 나오면 안 된다', () => { // 버그 당시의 정확한 출력. 상수를 되돌리면 이 테스트부터 깨진다. const g = latLonToKmaGrid(37.5665, 126.978); assert.notDeepEqual(g, { nx: 61, ny: 128 }); }); });