tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

io_run_test.c (8213B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include "helpers.h"
      4 
      5 static arb_handle_t make_pure(arb_ctx_t* ctx, arb_handle_t val) {
      6     arb_handle_t zero = checked_arb_of_number(ctx, 0);
      7     return checked_arb_fork(ctx, zero, val);
      8 }
      9 
     10 static arb_handle_t make_io_sentinel(arb_ctx_t* ctx, arb_handle_t action) {
     11     arb_handle_t sentinel = checked_arb_of_string(ctx, "tricuIO");
     12     arb_handle_t version = checked_arb_of_number(ctx, 1);
     13     arb_handle_t version_action = checked_arb_fork(ctx, version, action);
     14     return checked_arb_fork(ctx, sentinel, version_action);
     15 }
     16 
     17 int main(void) {
     18     arb_ctx_t* ctx = arboricx_init();
     19     if (!ctx) {
     20         fprintf(stderr, "Failed to initialize Arboricx context\n");
     21         return 1;
     22     }
     23 
     24     arb_io_perms_t perms = { 0, 0 };
     25 
     26     /* Test 1: pure "hello" wrapped in IO sentinel */
     27     {
     28         arb_handle_t hello = checked_arb_of_string(ctx, "hello");
     29         arb_handle_t pure_hello = make_pure(ctx, hello);
     30         arb_handle_t program = make_io_sentinel(ctx, pure_hello);
     31 
     32         arb_handle_t result = checked_arb_run_io(ctx, program, &perms);
     33         if (result == 0) {
     34             fprintf(stderr, "FAIL: pure hello returned 0\n");
     35             arboricx_free(ctx);
     36             return 1;
     37         }
     38 
     39         uint8_t* decoded;
     40         size_t decoded_len;
     41         if (!(arb_to_string(ctx, result, &decoded, &decoded_len) == ARB_OK) ||
     42             decoded_len != 5 || memcmp(decoded, "hello", 5) != 0) {
     43             fprintf(stderr, "FAIL: pure hello result mismatch\n");
     44             arboricx_free(ctx);
     45             return 1;
     46         }
     47         arboricx_free_buf(ctx, decoded, decoded_len);
     48         printf("PASS: pure hello\n");
     49     }
     50 
     51     /* Test 2: bind (pure "a") (\_ : pure "done") */
     52     {
     53         arb_handle_t a = checked_arb_of_string(ctx, "a");
     54         arb_handle_t done = checked_arb_of_string(ctx, "done");
     55         arb_handle_t pure_a = make_pure(ctx, a);
     56         arb_handle_t pure_done = make_pure(ctx, done);
     57 
     58         /* K pure_done = Fork Leaf pure_done */
     59         arb_handle_t k = checked_arb_fork(ctx, checked_arb_leaf(ctx), pure_done);
     60         arb_handle_t bind_pair = checked_arb_fork(ctx, pure_a, k);
     61         arb_handle_t one = checked_arb_of_number(ctx, 1);
     62         arb_handle_t bind_action = checked_arb_fork(ctx, one, bind_pair);
     63         arb_handle_t program = make_io_sentinel(ctx, bind_action);
     64 
     65         arb_handle_t result = checked_arb_run_io(ctx, program, &perms);
     66         if (result == 0) {
     67             fprintf(stderr, "FAIL: bind returned 0\n");
     68             arboricx_free(ctx);
     69             return 1;
     70         }
     71 
     72         uint8_t* decoded;
     73         size_t decoded_len;
     74         if (!(arb_to_string(ctx, result, &decoded, &decoded_len) == ARB_OK) ||
     75             decoded_len != 4 || memcmp(decoded, "done", 4) != 0) {
     76             fprintf(stderr, "FAIL: bind result mismatch\n");
     77             arboricx_free(ctx);
     78             return 1;
     79         }
     80         arboricx_free_buf(ctx, decoded, decoded_len);
     81         printf("PASS: bind pure\n");
     82     }
     83 
     84     /* Test 3: putStr "test" (no permissions needed) */
     85     {
     86         arb_handle_t test = checked_arb_of_string(ctx, "test");
     87         arb_handle_t ten = checked_arb_of_number(ctx, 10);
     88         arb_handle_t putStr_action = checked_arb_fork(ctx, ten, test);
     89         arb_handle_t program = make_io_sentinel(ctx, putStr_action);
     90 
     91         printf("EXPECT: test\n");
     92         arb_handle_t result = checked_arb_run_io(ctx, program, &perms);
     93         if (result == 0) {
     94             fprintf(stderr, "FAIL: putStr returned 0\n");
     95             arboricx_free(ctx);
     96             return 1;
     97         }
     98         if (!checked_arb_is_leaf(ctx, result)) {
     99             fprintf(stderr, "FAIL: putStr should return Leaf\n");
    100             arboricx_free(ctx);
    101             return 1;
    102         }
    103         printf("PASS: putStr\n");
    104     }
    105 
    106     /* Test 4: readFile without permission returns err */
    107     {
    108         arb_handle_t path = checked_arb_of_string(ctx, "/etc/passwd");
    109         arb_handle_t twenty = checked_arb_of_number(ctx, 20);
    110         arb_handle_t readFile_action = checked_arb_fork(ctx, twenty, path);
    111         arb_handle_t program = make_io_sentinel(ctx, readFile_action);
    112 
    113         arb_handle_t result = checked_arb_run_io(ctx, program, &perms);
    114         if (result == 0) {
    115             fprintf(stderr, "FAIL: readFile denied returned 0\n");
    116             arboricx_free(ctx);
    117             return 1;
    118         }
    119 
    120         /* Should be an err result: Fork Leaf (Fork code Leaf) */
    121         arb_handle_t left, right;
    122         if (!(arb_get_fork_children(ctx, result, &left, &right) == ARB_OK) ||
    123             !checked_arb_is_leaf(ctx, left)) {
    124             fprintf(stderr, "FAIL: readFile denied should be err result\n");
    125             arboricx_free(ctx);
    126             return 1;
    127         }
    128 
    129         arb_handle_t code, rest;
    130         if (!(arb_get_fork_children(ctx, right, &code, &rest) == ARB_OK) ||
    131             !checked_arb_is_leaf(ctx, rest)) {
    132             fprintf(stderr, "FAIL: readFile denied err shape mismatch\n");
    133             arboricx_free(ctx);
    134             return 1;
    135         }
    136 
    137         uint8_t* message;
    138         size_t message_len;
    139         const char* expected = "permission denied";
    140         if (!(arb_to_string(ctx, code, &message, &message_len) == ARB_OK) ||
    141             message_len != strlen(expected) ||
    142             memcmp(message, expected, message_len) != 0) {
    143             fprintf(stderr, "FAIL: readFile denied should carry a text error\n");
    144             arboricx_free(ctx);
    145             return 1;
    146         }
    147         arboricx_free_buf(ctx, message, message_len);
    148         printf("PASS: readFile denied\n");
    149     }
    150 
    151     /* Test 5: readFile with permission succeeds */
    152     {
    153         /* Create a temp file first */
    154         const char* tmp = "/tmp/tricu_io_test.txt";
    155         FILE* f = fopen(tmp, "w");
    156         if (!f) {
    157             fprintf(stderr, "FAIL: could not create temp file\n");
    158             arboricx_free(ctx);
    159             return 1;
    160         }
    161         fprintf(f, "hi");
    162         fclose(f);
    163 
    164         arb_io_perms_t unsafe_perms = { 1, 0 };
    165         arb_handle_t path = checked_arb_of_string(ctx, tmp);
    166         arb_handle_t twenty = checked_arb_of_number(ctx, 20);
    167         arb_handle_t readFile_action = checked_arb_fork(ctx, twenty, path);
    168         arb_handle_t program = make_io_sentinel(ctx, readFile_action);
    169 
    170         arb_handle_t result = checked_arb_run_io(ctx, program, &unsafe_perms);
    171         if (result == 0) {
    172             fprintf(stderr, "FAIL: readFile allowed returned 0\n");
    173             arboricx_free(ctx);
    174             return 1;
    175         }
    176 
    177         /* Should be ok result: Fork (Stem Leaf) (Fork val Leaf) */
    178         arb_handle_t ok_tag, ok_rest;
    179         if (!(arb_get_fork_children(ctx, result, &ok_tag, &ok_rest) == ARB_OK) ||
    180             !checked_arb_is_stem(ctx, ok_tag)) {
    181             fprintf(stderr, "FAIL: readFile allowed should be ok result\n");
    182             arboricx_free(ctx);
    183             return 1;
    184         }
    185 
    186         arb_handle_t val, leaf;
    187         if (!(arb_get_fork_children(ctx, ok_rest, &val, &leaf) == ARB_OK) ||
    188             !checked_arb_is_leaf(ctx, leaf)) {
    189             fprintf(stderr, "FAIL: readFile allowed ok shape mismatch\n");
    190             arboricx_free(ctx);
    191             return 1;
    192         }
    193 
    194         uint8_t* decoded;
    195         size_t decoded_len;
    196         if (!(arb_to_string(ctx, val, &decoded, &decoded_len) == ARB_OK) ||
    197             decoded_len != 2 || memcmp(decoded, "hi", 2) != 0) {
    198             fprintf(stderr, "FAIL: readFile allowed contents mismatch\n");
    199             arboricx_free(ctx);
    200             return 1;
    201         }
    202         arboricx_free_buf(ctx, decoded, decoded_len);
    203         printf("PASS: readFile allowed\n");
    204     }
    205 
    206     /* Test 6: invalid sentinel returns 0 */
    207     {
    208         arb_handle_t bad = checked_arb_fork(ctx, checked_arb_leaf(ctx), checked_arb_leaf(ctx));
    209         arb_handle_t result = 123;
    210         arb_status_t failure = arb_run_io(ctx, bad, &perms, &result);
    211         if (failure != ARB_IO_ERROR || result != 123) {
    212             fprintf(stderr, "FAIL: invalid sentinel should return 0\n");
    213             arboricx_free(ctx);
    214             return 1;
    215         }
    216         printf("PASS: invalid sentinel\n");
    217     }
    218 
    219     arboricx_free(ctx);
    220     printf("\nAll IO run tests passed.\n");
    221     return 0;
    222 }