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 }