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 }