/* * Round-trips the JS writer's real output through the C reader. * * The writer (src/pkjs/index.js) and the reader (src/c/main.c) are two implementations * of one format, in two languages, that never run in the same process. Nothing but a * test like this can catch them drifting apart — and drift decodes as plausible-looking * garbage rather than as an error, which is the failure worth spending a harness on. * * Build: see run-tests.sh. Reads the payload as hex on stdin. */ #include "pebble_stub.h" /* main.c includes ; the build passes -include pebble_stub.h and -Dpebble_h so that include resolves to nothing. See run-tests.sh. */ #define main pebble_main /* keep main.c's entry point out of the way */ #include "../src/c/main.c" #undef main static int failures = 0; static void check(const char *label, bool ok) { printf(" %s %s\n", ok ? "PASS" : "FAIL", label); if (!ok) failures++; } /* The toggles line is a second format shared by the same two implementations — packed in src/pkjs/index.js, parsed in src/c/main.c — so it gets the same treatment as the plan: the JS writes it, this reads it, and a disagreement is a failed test rather than a watch screen that quietly says the wrong microphone is live. */ static void check_toggles(const char *path) { FILE *file = fopen(path, "rb"); if (!file) { printf(" FAIL could not open %s\n", path); failures++; return; } static char packed[512]; size_t length = fread(packed, 1, sizeof(packed) - 1, file); packed[length] = 0; fclose(file); parse_toggles(packed); check("three toggles parsed", s_toggle_count == 3); if (s_toggle_count != 3) return; check("first name survives an apostrophe", strcmp(s_toggles[0].name, "Amir's desktop") == 0); check("first is on", s_toggles[0].on); check("first detail is the live mic", strcmp(s_toggles[0].detail, "Loggia") == 0); /* The JS truncates to the C buffer sizes, so a long name must arrive already short rather than being cut differently on each side. */ check("long name truncated by the writer", strlen(s_toggles[1].name) == 21); check("second is off", !s_toggles[1].on); check("long detail truncated by the writer", strlen(s_toggles[1].detail) == 15); /* A value containing the field separator would split into extra fields; the writer strips them, and this is what proves it still does. */ check("separators stripped from values", strcmp(s_toggles[2].name, "Weird name") == 0); check("third detail intact", strcmp(s_toggles[2].detail, "Desk") == 0); parse_toggles(""); check("empty payload means no toggles", s_toggle_count == 0); parse_toggles("Half a record|1"); check("truncated record still yields a safe row", s_toggle_count == 1 && s_toggles[0].on && s_toggles[0].detail[0] == 0); } int main(int argc, char **argv) { static uint8_t buffer[4096]; uint16_t length = 0; unsigned int byte; while (scanf("%2x", &byte) == 1 && length < sizeof(buffer)) buffer[length++] = (uint8_t)byte; printf("payload: %u bytes\n", length); bool ok = parse_plan(buffer, length); check("parses", ok); if (!ok) { printf(" status: %s\n", s_status); return 1; } check("room count is 3", s_room_count == 3); check("room 0 is named Kitchen", strcmp(s_rooms[0].name, "Kitchen") == 0); check("room 0 is occupied", s_rooms[0].state == 1); check("room 0 has 4 vertices", s_rooms[0].vertex_count == 4); check("room 0 has 1 occupant", s_rooms[0].occupant_count == 1); check("occupant initial is A", s_rooms[0].occupants[0].initial == 'A'); check("occupant colour index 0", s_rooms[0].occupants[0].colour == 0); check("occupant has a position", s_rooms[0].occupants[0].has_position); check("occupant name survived", strcmp(s_rooms[0].occupants[0].name, "Amir") == 0); check("room 1 is named Loggia", strcmp(s_rooms[1].name, "Loggia") == 0); /* A radar target outranks "HA never reports this area": somebody IS in there, and a positive detection beats no data. The first draft of this test asserted the opposite and was wrong. */ check("room 1 is occupied (radar, nobody named)", s_rooms[1].state == 1); check("room 1 has an anonymous target", s_rooms[1].target_count == 1); check("room 1 has no occupants", s_rooms[1].occupant_count == 0); check("room 2 is the unknown state", s_rooms[2].state == 2); check("room 2 has no targets", s_rooms[2].target_count == 0); check("1 unplaced person", s_unplaced_count == 1); check("unplaced is Bibi", strcmp(s_unplaced[0].name, "Bibi") == 0); /* A truncated payload must be refused wholesale, never half-decoded: a plan missing its last rooms looks exactly like a real plan. */ bool truncated = parse_plan(buffer, length / 2); check("truncated payload refused", !truncated && s_room_count == 0); /* A version bump on the phone must not decode as garbage here. */ buffer[0] = 99; check("wrong version refused", !parse_plan(buffer, length)); if (argc > 1) { printf("\ntoggles line:\n"); check_toggles(argv[1]); } printf(failures ? "\nFAILURES: %d\n" : "\nall wire-format checks passed\n", failures); return failures ? 1 : 0; }