tricu

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

io_run_test.c (7402B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include "arboricx.h"
      4 
      5 static uint32_t make_pure(arb_ctx_t* ctx, uint32_t val) {
      6     uint32_t zero = arb_of_number(ctx, 0);
      7     return arb_fork(ctx, zero, val);
      8 }
      9 
     10 static uint32_t make_io_sentinel(arb_ctx_t* ctx, uint32_t action) {
     11     uint32_t sentinel = arb_of_string(ctx, "tricuIO");
     12     uint32_t version = arb_of_number(ctx, 1);
     13     uint32_t version_action = arb_fork(ctx, version, action);
     14     return 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         uint32_t hello = arb_of_string(ctx, "hello");
     29         uint32_t pure_hello = make_pure(ctx, hello);
     30         uint32_t program = make_io_sentinel(ctx, pure_hello);
     31 
     32         uint32_t result = 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) ||
     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         uint32_t a = arb_of_string(ctx, "a");
     54         uint32_t done = arb_of_string(ctx, "done");
     55         uint32_t pure_a = make_pure(ctx, a);
     56         uint32_t pure_done = make_pure(ctx, done);
     57 
     58         /* K pure_done = Fork Leaf pure_done */
     59         uint32_t k = arb_fork(ctx, arb_leaf(ctx), pure_done);
     60         uint32_t bind_pair = arb_fork(ctx, pure_a, k);
     61         uint32_t one = arb_of_number(ctx, 1);
     62         uint32_t bind_action = arb_fork(ctx, one, bind_pair);
     63         uint32_t program = make_io_sentinel(ctx, bind_action);
     64 
     65         uint32_t result = 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) ||
     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         uint32_t test = arb_of_string(ctx, "test");
     87         uint32_t ten = arb_of_number(ctx, 10);
     88         uint32_t putStr_action = arb_fork(ctx, ten, test);
     89         uint32_t program = make_io_sentinel(ctx, putStr_action);
     90 
     91         printf("EXPECT: test\n");
     92         uint32_t result = 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 (!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         uint32_t path = arb_of_string(ctx, "/etc/passwd");
    109         uint32_t twenty = arb_of_number(ctx, 20);
    110         uint32_t readFile_action = arb_fork(ctx, twenty, path);
    111         uint32_t program = make_io_sentinel(ctx, readFile_action);
    112 
    113         uint32_t result = 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         uint32_t left, right;
    122         if (!arb_get_fork_children(ctx, result, &left, &right) ||
    123             !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         uint32_t code, rest;
    130         if (!arb_get_fork_children(ctx, right, &code, &rest) ||
    131             !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         uint64_t code_num;
    138         if (!arb_to_number(ctx, code, &code_num) || code_num != 20) {
    139             fprintf(stderr, "FAIL: readFile denied code should be 20, got %llu\n",
    140                     (unsigned long long)code_num);
    141             arboricx_free(ctx);
    142             return 1;
    143         }
    144         printf("PASS: readFile denied\n");
    145     }
    146 
    147     /* Test 5: readFile with permission succeeds */
    148     {
    149         /* Create a temp file first */
    150         const char* tmp = "/tmp/tricu_io_test.txt";
    151         FILE* f = fopen(tmp, "w");
    152         if (!f) {
    153             fprintf(stderr, "FAIL: could not create temp file\n");
    154             arboricx_free(ctx);
    155             return 1;
    156         }
    157         fprintf(f, "hi");
    158         fclose(f);
    159 
    160         arb_io_perms_t unsafe_perms = { 1, 0 };
    161         uint32_t path = arb_of_string(ctx, tmp);
    162         uint32_t twenty = arb_of_number(ctx, 20);
    163         uint32_t readFile_action = arb_fork(ctx, twenty, path);
    164         uint32_t program = make_io_sentinel(ctx, readFile_action);
    165 
    166         uint32_t result = arb_run_io(ctx, program, &unsafe_perms);
    167         if (result == 0) {
    168             fprintf(stderr, "FAIL: readFile allowed returned 0\n");
    169             arboricx_free(ctx);
    170             return 1;
    171         }
    172 
    173         /* Should be ok result: Fork (Stem Leaf) (Fork val Leaf) */
    174         uint32_t ok_tag, ok_rest;
    175         if (!arb_get_fork_children(ctx, result, &ok_tag, &ok_rest) ||
    176             !arb_is_stem(ctx, ok_tag)) {
    177             fprintf(stderr, "FAIL: readFile allowed should be ok result\n");
    178             arboricx_free(ctx);
    179             return 1;
    180         }
    181 
    182         uint32_t val, leaf;
    183         if (!arb_get_fork_children(ctx, ok_rest, &val, &leaf) ||
    184             !arb_is_leaf(ctx, leaf)) {
    185             fprintf(stderr, "FAIL: readFile allowed ok shape mismatch\n");
    186             arboricx_free(ctx);
    187             return 1;
    188         }
    189 
    190         uint8_t* decoded;
    191         size_t decoded_len;
    192         if (!arb_to_string(ctx, val, &decoded, &decoded_len) ||
    193             decoded_len != 2 || memcmp(decoded, "hi", 2) != 0) {
    194             fprintf(stderr, "FAIL: readFile allowed contents mismatch\n");
    195             arboricx_free(ctx);
    196             return 1;
    197         }
    198         arboricx_free_buf(ctx, decoded, decoded_len);
    199         printf("PASS: readFile allowed\n");
    200     }
    201 
    202     /* Test 6: invalid sentinel returns 0 */
    203     {
    204         uint32_t bad = arb_fork(ctx, arb_leaf(ctx), arb_leaf(ctx));
    205         uint32_t result = arb_run_io(ctx, bad, &perms);
    206         if (result != 0) {
    207             fprintf(stderr, "FAIL: invalid sentinel should return 0\n");
    208             arboricx_free(ctx);
    209             return 1;
    210         }
    211         printf("PASS: invalid sentinel\n");
    212     }
    213 
    214     arboricx_free(ctx);
    215     printf("\nAll IO run tests passed.\n");
    216     return 0;
    217 }