내장 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('유통기한 테스트 통과');