Report sign/house in significant transits; back up user.properties outside dist/

This commit is contained in:
ml
2026-07-05 17:18:20 +02:00
parent 28558b4343
commit 1136e3257a
9 changed files with 197 additions and 50 deletions
+40 -5
View File
@@ -41,14 +41,16 @@ static void test_json_parse_rejects_malformed(void) {
}
/* A trimmed-but-structurally-faithful fixture matching deck-engine's real
* --format json shape: natal/spread sections are present with decoy
* content the loader must skip over without understanding their schema,
* to prove it navigates by key path rather than assuming any position. */
* --format json shape: "spread" is present with decoy content the loader
* must skip over without understanding its schema, to prove it navigates
* by key path rather than assuming any position. "natal"/"transits"
* bodies are real (if partial) - reading_load_json now parses sign/house
* from them for display, alongside the aspects used for scoring. */
static const char *k_fixture =
"{"
" \"natal\": {\"bodies\": [{\"body\": \"sun\", \"sign\": \"taurus\"}], \"houses\": []},"
" \"natal\": {\"bodies\": [{\"body\": \"sun\", \"sign\": \"taurus\", \"house\": 3}], \"houses\": []},"
" \"transits\": {"
" \"bodies\": [{\"body\": \"sun\", \"sign\": \"cancer\"}],"
" \"bodies\": [{\"body\": \"sun\", \"sign\": \"cancer\", \"house\": 5}],"
" \"moon_phase\": \"full\","
" \"aspects\": ["
" {\"transiting_planet\": \"pluto\", \"natal_planet\": \"moon\", \"type\": \"opposition\", \"orb\": 0.2},"
@@ -75,6 +77,37 @@ static void test_reading_load_json_extracts_aspects(void) {
printf("PASS test_reading_load_json_extracts_aspects\n");
}
static void test_reading_load_json_extracts_body_sign_and_house(void) {
DailyReading reading;
bool ok = reading_load_json(k_fixture, strlen(k_fixture), &reading);
assert(ok);
assert(reading.natal.bodies[PLANET_SUN].sign == SIGN_TAURUS);
assert(reading.natal.bodies[PLANET_SUN].house == 3);
assert(reading.transits.bodies[PLANET_SUN].sign == SIGN_CANCER);
assert(reading.transits.bodies[PLANET_SUN].house == 5);
/* Bodies missing from the fixture (e.g. the Moon) get the "no data"
* sentinel rather than a garbage house number. */
assert(reading.natal.bodies[PLANET_MOON].house == 0);
assert(reading.transits.bodies[PLANET_MOON].house == 0);
printf("PASS test_reading_load_json_extracts_body_sign_and_house\n");
}
static void test_reading_load_json_unknown_body_slug_is_skipped_not_fatal(void) {
const char *text =
"{\"natal\": {\"bodies\": [{\"body\": \"xenu\", \"sign\": \"taurus\", \"house\": 3}]},"
" \"transits\": {\"aspects\": []}}";
DailyReading reading;
bool ok = reading_load_json(text, strlen(text), &reading);
assert(ok);
assert(reading.transits.aspect_count == 0);
printf("PASS test_reading_load_json_unknown_body_slug_is_skipped_not_fatal\n");
}
static void test_reading_load_json_empty_aspects_is_valid(void) {
const char *text = "{\"transits\": {\"aspects\": []}}";
DailyReading reading;
@@ -113,6 +146,8 @@ int main(void) {
test_json_parse_basic_shapes();
test_json_parse_rejects_malformed();
test_reading_load_json_extracts_aspects();
test_reading_load_json_extracts_body_sign_and_house();
test_reading_load_json_unknown_body_slug_is_skipped_not_fatal();
test_reading_load_json_empty_aspects_is_valid();
test_reading_load_json_rejects_missing_transits();
test_reading_load_json_rejects_unknown_slug();