내장 Explanatory 스타일 2회차 · Claude Code · Opus 5.5 · 생각 깊이 중간 · 가상 카페 재고 코드 · 목록

내장 Explanatory 스타일 2회차

클로드의 마지막 답변 (claude -p 화면에 찍히는 부분, 그대로)

`src/stock.mjs`에 두 함수를 추가했고, `node test/stock.test.mjs`로 돌린 기존 테스트와 새 테스트가 모두 통과했습니다. **추가한 함수** - `expiringSoon(items, today)`: 오늘부터 남은 일수가 0~3일인 재료의 이름을 돌려줍니다. 오늘과 3일 뒤도 포함됩니다. - `expired(items, today)`: 남은 일수가 0보다 작은 재료, 즉 유통기한이 이미 지난 재료의 이름을 돌려줍니다. - 두 함수 모두 들어온 순서를 그대로 유지합니다. **추가한 테스트** (`test/stock.test.mjs`) - 경계값: 오늘(0일), 3일 뒤(포함), 4일 뒤(제외), 어제(지남) - 섞인 순서로 넣어도 들어온 순서대로 나오는지 - 월말 경계: 10-30 기준으로 11-01이 3일 이내로 잡히는지 - 빈 배열 `★ Insight ─────────────────────────────────────` - 유통기한이 딱 오늘인 재료는 `expiringSoon`에만 들어가고 `expired`에는 들어가지 않습니다. 두 조건(`0~3`과 `< 0`)이 겹치지 않아서 한 재료가 두 목록에 동시에 나오는 일이 없습니다. - 4일 뒤를 테스트에 넣은 이유는 `<= 3`을 실수로 `< 4`나 `<= 4`로 바꿨을 때 테스트가 바로 실패하게 하려는 것입니다. 이런 경계 실수는 3일 뒤만 확인해서는 잡히지 않고, 바로 바깥값까지 확인해야 잡힙니다. - 문자열 날짜를 직접 비교하지 않고 `daysBetween`으로 일수를 구해 판정하기 때문에, 월이나 연도가 바뀌는 날짜도 따로 처리할 필요가 없습니다. `─────────────────────────────────────────────────`

바뀐 코드 (git diff)

diff --git a/src/stock.mjs b/src/stock.mjs
index f81b897..2a3dca6 100644
--- a/src/stock.mjs
+++ b/src/stock.mjs
@@ -14,6 +14,19 @@ export function lowStock(items) {
   return items.filter((it) => it.qty < it.minQty).map((it) => it.name);
 }
 
+export function expiringSoon(items, today) {
+  return items
+    .filter((it) => {
+      const left = daysBetween(today, it.expires);
+      return left >= 0 && left <= 3;
+    })
+    .map((it) => it.name);
+}
+
+export function expired(items, today) {
+  return items.filter((it) => daysBetween(today, it.expires) < 0).map((it) => it.name);
+}
+
 export function orderList(items) {
   return items
     .filter((it) => it.qty < it.minQty)
diff --git a/test/stock.test.mjs b/test/stock.test.mjs
index 71de632..a72c5f0 100644
--- a/test/stock.test.mjs
+++ b/test/stock.test.mjs
@@ -1,5 +1,5 @@
 import assert from 'node:assert/strict';
-import { lowStock, orderList, daysBetween } from '../src/stock.mjs';
+import { lowStock, orderList, daysBetween, expiringSoon, expired } from '../src/stock.mjs';
 const items = [
   { name: '우유', qty: 3, unit: 'L', expires: '2026-10-20', minQty: 5 },
   { name: '원두', qty: 4, unit: 'kg', expires: '2027-01-10', minQty: 2 },
@@ -8,3 +8,19 @@ assert.deepEqual(lowStock(items), ['우유']);
 assert.deepEqual(orderList(items), [{ name: '우유', need: 7, unit: 'L' }]);
 assert.equal(daysBetween('2026-10-18', '2026-10-20'), 2);
 console.log('기본 테스트 통과');
+
+const fridge = [
+  { name: '생크림', qty: 1, unit: 'L', expires: '2026-10-21', minQty: 1 }, // D+3 (경계, 포함)
+  { name: '우유', qty: 3, unit: 'L', expires: '2026-10-18', minQty: 5 }, // 오늘 (포함)
+  { name: '크림치즈', qty: 2, unit: 'kg', expires: '2026-10-17', minQty: 1 }, // 어제 (지남)
+  { name: '버터', qty: 1, unit: 'kg', expires: '2026-10-22', minQty: 1 }, // D+4 (제외)
+  { name: '요거트', qty: 1, unit: 'L', expires: '2026-09-30', minQty: 1 }, // 지남
+  { name: '시럽', qty: 1, unit: 'L', expires: '2026-11-01', minQty: 1 }, // 월 넘어감 (제외)
+];
+assert.deepEqual(expiringSoon(fridge, '2026-10-18'), ['생크림', '우유']);
+assert.deepEqual(expired(fridge, '2026-10-18'), ['크림치즈', '요거트']);
+// 월말 경계: 10-30 기준 D+3 = 11-02
+assert.deepEqual(expiringSoon(fridge, '2026-10-30'), ['시럽']);
+assert.deepEqual(expiringSoon([], '2026-10-18'), []);
+assert.deepEqual(expired([], '2026-10-18'), []);
+console.log('유통기한 테스트 통과');