Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/cronometer_api_mcp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,14 +728,29 @@ def create_custom_food(
"defaultMeasureId": 0,
"comments": None,
"alternateId": None,
# The first measure becomes the server-assigned default.
"measures": [
{
"id": 0,
"name": serving_name,
"value": serving_grams,
"amount": 1.0,
"type": "Atomic",
}
"type": "Weight",
},
{
"id": 0,
"name": "g",
"value": 1.0,
"amount": 1.0,
"type": "Weight",
},
{
"id": 0,
"name": "oz",
"value": _OZ_GRAMS,
"amount": 1.0,
"type": "Weight",
},
],
"labelType": "AMERICAN_2016",
"nutrients": nutrients,
Expand Down
32 changes: 31 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,10 +868,40 @@ def test_import_recipe_rejects_blank_input(tmp_path, monkeypatch):


# ---------------------------------------------------------------------------
# create_custom_food: extra_nutrients
# create_custom_food
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("serving_grams", [100.0, 200.0])
def test_create_custom_food_supports_weight_units(tmp_path, serving_grams):
client, state = make_cold_client(tmp_path, [{"result": "SUCCESS", "id": 555}])

client.create_custom_food(
"Test Food",
calories=200,
protein_g=10,
fat_g=5,
carbs_g=20,
serving_name="plate",
serving_grams=serving_grams,
)

data = state["payloads"][0]["data"]
serving, grams, ounces = data["measures"]
assert [m["name"] for m in data["measures"]] == ["plate", "g", "oz"]
assert all(m["type"] == "Weight" for m in data["measures"])
assert all(m["amount"] == 1.0 for m in data["measures"])
assert serving["value"] == serving_grams
assert grams["value"] == 1.0
assert ounces["value"] == pytest.approx(28.3495231)

nutrients = {n["id"]: n["amount"] for n in data["nutrients"]}
assert nutrients[208] == 200 * 100 / serving_grams
assert nutrients[203] == 10 * 100 / serving_grams
assert nutrients[204] == 5 * 100 / serving_grams
assert nutrients[205] == 20 * 100 / serving_grams


def test_create_custom_food_extra_nutrients_payload(tmp_path):
"""extra_nutrients are appended, normalized to per-100g like the macros."""
client, state = make_cold_client(tmp_path, [{"result": "SUCCESS", "id": 555}])
Expand Down
28 changes: 28 additions & 0 deletions tests/test_custom_food_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,34 @@ def test_update_custom_food_serving_overrides_measure_and_scale(tmp_path):
assert nutrients_by_id(state["payloads"][1])[208] == 200.0 # 400 per 200 g


def test_update_custom_food_preserves_weight_units(tmp_path):
food = custom_food()
food["measures"][0]["type"] = "Weight"
weight_units = [
{"id": 901, "name": "g", "amount": 1, "value": 1, "type": "Weight"},
{
"id": 902,
"name": "oz",
"amount": 1,
"value": 28.3495231,
"type": "Weight",
},
]
food["measures"].extend(dict(unit) for unit in weight_units)
client, state = make_cold_client(tmp_path, [food, OK])

client.update_custom_food(
FOOD_ID, serving_name="plate", serving_grams=200, calories=400
)

data = state["payloads"][1]["data"]
assert data["defaultMeasureId"] == 900
assert data["measures"][0]["id"] == 900
assert data["measures"][0]["value"] == 200
assert data["measures"][1:] == weight_units
assert nutrients_by_id(state["payloads"][1])[208] == 200


def weight_default_food() -> dict:
"""A food first saved as "400 g": its default measure is 400 units of a
Weight measure, which the app renders as "400 <name>"."""
Expand Down
Loading