Skip to content

Commit d4ea979

Browse files
committed
fix: update file paths for Android compatibility in tests and define platform-specific temporary directories
1 parent fe736c3 commit d4ea979

2 files changed

Lines changed: 49 additions & 45 deletions

File tree

.github/workflows/main.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -531,11 +531,6 @@ jobs:
531531
script: |
532532
adb root
533533
adb remount
534-
# Android's `/` is read-only by default even after `adb root` —
535-
# remount it rw and create /tmp + /var so the test_adam binary's
536-
# POSIX-style hardcoded paths resolve. Log mount/mkdir status to
537-
# surface diagnostics if something is wrong.
538-
adb shell "mount -o remount,rw / 2>&1; mkdir -p /tmp /var 2>&1; ls -ld /tmp /var"
539534
adb push ${{ github.workspace }}/commands.sh /data/local/tmp/
540535
adb push ${{ github.workspace }}/sqlite3 /data/local/tmp/
541536
adb push ${{ github.workspace }}/dist /data/local/tmp/

test/test_adam.c

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@
3131
#define adam_mkdir(p, m) mkdir((p), (m))
3232
#endif
3333

34+
// Platform-portable temp / second directory used by file-sandbox tests.
35+
// Android's `/` is a read-only rootfs (no mkdir, no symlink); the writable
36+
// scratch dir is `/data/local/tmp`. Other platforms keep the POSIX defaults.
37+
// String concatenation lets us inline these into both plain paths
38+
// (`TEST_TMP "/foo.db"`) and JSON args (`"{\"path\":\"" TEST_TMP "/foo\"}"`).
39+
#ifdef __ANDROID__
40+
#define TEST_TMP "/data/local/tmp"
41+
#define TEST_VAR "/data"
42+
#else
43+
#define TEST_TMP "/tmp"
44+
#define TEST_VAR "/var"
45+
#endif
46+
3447
#ifndef ADAM_NO_PTHREADS
3548
#include <pthread.h>
3649
#endif
@@ -2453,7 +2466,7 @@ TEST(local_with_stream_callback) {
24532466
#include <unistd.h>
24542467

24552468
TEST(session_open_close) {
2456-
const char *path = "/tmp/adam_test_session.db";
2469+
const char *path = TEST_TMP "/adam_test_session.db";
24572470
unlink(path);
24582471
adam_memory_t *mem = adam_memory_open(path);
24592472
ASSERT_NOT_NULL(mem);
@@ -2462,7 +2475,7 @@ TEST(session_open_close) {
24622475
}
24632476

24642477
TEST(session_save_load_simple) {
2465-
const char *path = "/tmp/adam_test_session2.db";
2478+
const char *path = TEST_TMP "/adam_test_session2.db";
24662479
unlink(path);
24672480
adam_memory_t *mem = adam_memory_open(path);
24682481
ASSERT_NOT_NULL(mem);
@@ -2499,7 +2512,7 @@ TEST(session_save_load_simple) {
24992512
}
25002513

25012514
TEST(session_save_load_with_tool_calls) {
2502-
const char *path = "/tmp/adam_test_session3.db";
2515+
const char *path = TEST_TMP "/adam_test_session3.db";
25032516
unlink(path);
25042517
adam_memory_t *mem = adam_memory_open(path);
25052518

@@ -2546,7 +2559,7 @@ TEST(session_save_load_with_tool_calls) {
25462559
}
25472560

25482561
TEST(session_list_and_delete) {
2549-
const char *path = "/tmp/adam_test_session4.db";
2562+
const char *path = TEST_TMP "/adam_test_session4.db";
25502563
unlink(path);
25512564
adam_memory_t *mem = adam_memory_open(path);
25522565

@@ -2593,7 +2606,7 @@ TEST(session_list_and_delete) {
25932606

25942607
TEST(session_overwrite) {
25952608
// Saving the same session_id twice should replace the old data
2596-
const char *path = "/tmp/adam_test_session5.db";
2609+
const char *path = TEST_TMP "/adam_test_session5.db";
25972610
unlink(path);
25982611
adam_memory_t *mem = adam_memory_open(path);
25992612

@@ -2622,7 +2635,7 @@ TEST(session_overwrite) {
26222635

26232636
TEST(session_persistence_across_reopen) {
26242637
// Data survives closing and reopening the database
2625-
const char *path = "/tmp/adam_test_session6.db";
2638+
const char *path = TEST_TMP "/adam_test_session6.db";
26262639
unlink(path);
26272640

26282641
// Open, save, close
@@ -3552,47 +3565,47 @@ TEST(tool_file_read_sandbox) {
35523565
ASSERT(strstr(r.for_llm, "denied") != NULL);
35533566

35543567
// Allow /tmp
3555-
ASSERT_EQ(adam_settings_allow_dir(s, "/tmp"), ADAM_OK);
3568+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_TMP), ADAM_OK);
35563569

35573570
// Write a test file
3558-
FILE *f = fopen("/tmp/adam_test_read.txt", "w");
3571+
FILE *f = fopen(TEST_TMP "/adam_test_read.txt", "w");
35593572
ASSERT_NOT_NULL(f);
35603573
fprintf(f, "hello from adam test");
35613574
fclose(f);
35623575

35633576
// Read it — should succeed
35643577
arena_reset(a);
3565-
args = "{\"path\":\"/tmp/adam_test_read.txt\"}";
3578+
args = "{\"path\":\"" TEST_TMP "/adam_test_read.txt\"}";
35663579
r = adam_tool_file_read(a, s, args, strlen(args));
35673580
ASSERT_EQ(r.success, 1);
35683581
ASSERT_STR_EQ(r.for_llm, "hello from adam test");
35693582

35703583
// Try to escape sandbox
35713584
arena_reset(a);
3572-
args = "{\"path\":\"/tmp/../etc/hosts\"}";
3585+
args = "{\"path\":\"" TEST_TMP "/../etc/hosts\"}";
35733586
r = adam_tool_file_read(a, s, args, strlen(args));
35743587
ASSERT_EQ(r.success, 0);
35753588
ASSERT(strstr(r.for_llm, "denied") != NULL);
35763589

3577-
remove("/tmp/adam_test_read.txt");
3590+
remove(TEST_TMP "/adam_test_read.txt");
35783591
arena_destroy(a);
35793592
adam_settings_destroy(s);
35803593
}
35813594

35823595
TEST(tool_file_write_sandbox) {
35833596
arena_t *a = arena_create(4096);
35843597
adam_settings_t *s = adam_create_settings();
3585-
ASSERT_EQ(adam_settings_allow_dir(s, "/tmp"), ADAM_OK);
3598+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_TMP), ADAM_OK);
35863599

35873600
// Write a file
3588-
const char *args = "{\"path\":\"/tmp/adam_test_write.txt\","
3601+
const char *args = "{\"path\":\"" TEST_TMP "/adam_test_write.txt\","
35893602
"\"content\":\"test content\"}";
35903603
adam_tool_result_t r = adam_tool_file_write(a, s, args, strlen(args));
35913604
ASSERT_EQ(r.success, 1);
35923605
ASSERT(strstr(r.for_llm, "Wrote") != NULL);
35933606

35943607
// Verify contents
3595-
FILE *f = fopen("/tmp/adam_test_write.txt", "r");
3608+
FILE *f = fopen(TEST_TMP "/adam_test_write.txt", "r");
35963609
ASSERT_NOT_NULL(f);
35973610
char buf[64];
35983611
size_t n = fread(buf, 1, 63, f);
@@ -3602,12 +3615,12 @@ TEST(tool_file_write_sandbox) {
36023615

36033616
// Append
36043617
arena_reset(a);
3605-
args = "{\"path\":\"/tmp/adam_test_write.txt\","
3618+
args = "{\"path\":\"" TEST_TMP "/adam_test_write.txt\","
36063619
"\"content\":\" appended\",\"append\":true}";
36073620
r = adam_tool_file_write(a, s, args, strlen(args));
36083621
ASSERT_EQ(r.success, 1);
36093622

3610-
f = fopen("/tmp/adam_test_write.txt", "r");
3623+
f = fopen(TEST_TMP "/adam_test_write.txt", "r");
36113624
n = fread(buf, 1, 63, f);
36123625
buf[n] = '\0';
36133626
fclose(f);
@@ -3620,22 +3633,22 @@ TEST(tool_file_write_sandbox) {
36203633
ASSERT_EQ(r.success, 0);
36213634
ASSERT(strstr(r.for_llm, "denied") != NULL);
36223635

3623-
remove("/tmp/adam_test_write.txt");
3636+
remove(TEST_TMP "/adam_test_write.txt");
36243637
arena_destroy(a);
36253638
adam_settings_destroy(s);
36263639
}
36273640

36283641
TEST(tool_list_directory_sandbox) {
36293642
arena_t *a = arena_create(64 * 1024);
36303643
adam_settings_t *s = adam_create_settings();
3631-
ASSERT_EQ(adam_settings_allow_dir(s, "/tmp"), ADAM_OK);
3644+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_TMP), ADAM_OK);
36323645

36333646
// Create test directory with a file
3634-
adam_mkdir("/tmp/adam_test_dir", 0755);
3635-
FILE *f = fopen("/tmp/adam_test_dir/test.txt", "w");
3647+
adam_mkdir(TEST_TMP "/adam_test_dir", 0755);
3648+
FILE *f = fopen(TEST_TMP "/adam_test_dir/test.txt", "w");
36363649
if (f) { fputs("x", f); fclose(f); }
36373650

3638-
const char *args = "{\"path\":\"/tmp/adam_test_dir\"}";
3651+
const char *args = "{\"path\":\"" TEST_TMP "/adam_test_dir\"}";
36393652
adam_tool_result_t r = adam_tool_list_directory(a, s, args, strlen(args));
36403653
ASSERT_EQ(r.success, 1);
36413654
ASSERT(strstr(r.for_llm, "test.txt") != NULL);
@@ -3647,8 +3660,8 @@ TEST(tool_list_directory_sandbox) {
36473660
r = adam_tool_list_directory(a, s, args, strlen(args));
36483661
ASSERT_EQ(r.success, 0);
36493662

3650-
remove("/tmp/adam_test_dir/test.txt");
3651-
rmdir("/tmp/adam_test_dir");
3663+
remove(TEST_TMP "/adam_test_dir/test.txt");
3664+
rmdir(TEST_TMP "/adam_test_dir");
36523665
arena_destroy(a);
36533666
adam_settings_destroy(s);
36543667
}
@@ -3664,7 +3677,7 @@ TEST(tool_shell_exec_basic) {
36643677
ASSERT(strstr(r.for_llm, "denied") != NULL);
36653678

36663679
// Allow /tmp
3667-
ASSERT_EQ(adam_settings_allow_dir(s, "/tmp"), ADAM_OK);
3680+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_TMP), ADAM_OK);
36683681

36693682
// Simple echo
36703683
arena_reset(a);
@@ -3691,13 +3704,13 @@ TEST(tool_allow_dir) {
36913704
adam_settings_t *s = adam_create_settings();
36923705

36933706
ASSERT_EQ(s->allowed_dir_count, 0);
3694-
ASSERT_EQ(adam_settings_allow_dir(s, "/tmp"), ADAM_OK);
3707+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_TMP), ADAM_OK);
36953708
ASSERT_EQ(s->allowed_dir_count, 1);
3696-
ASSERT_EQ(adam_settings_allow_dir(s, "/var"), ADAM_OK);
3709+
ASSERT_EQ(adam_settings_allow_dir(s, TEST_VAR), ADAM_OK);
36973710
ASSERT_EQ(s->allowed_dir_count, 2);
36983711

36993712
// NULL params
3700-
ASSERT_EQ(adam_settings_allow_dir(NULL, "/tmp"), ADAM_ERR_INVALID_PARAM);
3713+
ASSERT_EQ(adam_settings_allow_dir(NULL, TEST_TMP), ADAM_ERR_INVALID_PARAM);
37013714
ASSERT_EQ(adam_settings_allow_dir(s, NULL), ADAM_ERR_INVALID_PARAM);
37023715

37033716
// Nonexistent dir
@@ -4892,18 +4905,18 @@ TEST(integration_json_output) {
48924905
TEST(integration_file_tools_sandbox) {
48934906
// Write a file, read it back, list directory — all sandboxed
48944907
adam_settings_t *s = adam_create_settings();
4895-
adam_settings_allow_dir(s, "/tmp");
4908+
adam_settings_allow_dir(s, TEST_TMP);
48964909
arena_t *a = arena_create(64 * 1024);
48974910

48984911
// Write
4899-
const char *w_args = "{\"path\":\"/tmp/adam_integ_test.txt\","
4912+
const char *w_args = "{\"path\":\"" TEST_TMP "/adam_integ_test.txt\","
49004913
"\"content\":\"Hello from integration test!\"}";
49014914
adam_tool_result_t wr = adam_tool_file_write(a, s, w_args, strlen(w_args));
49024915
ASSERT_EQ(wr.success, 1);
49034916

49044917
// Read back
49054918
arena_reset(a);
4906-
const char *r_args = "{\"path\":\"/tmp/adam_integ_test.txt\"}";
4919+
const char *r_args = "{\"path\":\"" TEST_TMP "/adam_integ_test.txt\"}";
49074920
adam_tool_result_t rr = adam_tool_file_read(a, s, r_args, strlen(r_args));
49084921
ASSERT_EQ(rr.success, 1);
49094922
ASSERT_STR_EQ(rr.for_llm, "Hello from integration test!");
@@ -4922,7 +4935,7 @@ TEST(integration_file_tools_sandbox) {
49224935
ASSERT_EQ(dr.success, 0);
49234936
ASSERT(strstr(dr.for_llm, "denied") != NULL);
49244937

4925-
remove("/tmp/adam_integ_test.txt");
4938+
remove(TEST_TMP "/adam_integ_test.txt");
49264939
arena_destroy(a);
49274940
adam_settings_destroy(s);
49284941
}
@@ -5133,15 +5146,11 @@ int main(void) {
51335146
printf("Adam Test Suite v%s\n", ADAM_VERSION_STRING);
51345147
printf("============================================================\n");
51355148

5136-
// Tests use hardcoded POSIX-style paths (`/tmp/...`, `/var`). Ensure
5137-
// both dirs exist before any test runs:
5138-
// - Linux/macOS: already there, EEXIST is fine
5139-
// - Windows MinGW: `/tmp` resolves to `<drive>:\tmp` (no MSYS path
5140-
// translation in MinGW binaries); we create it
5141-
// - Android: `/tmp` doesn't exist by default; needs adb root + remount
5142-
// (already done in CI) for mkdir at / to succeed
5143-
adam_mkdir("/tmp", 0755);
5144-
adam_mkdir("/var", 0755);
5149+
// TEST_TMP / TEST_VAR map to platform-writable dirs (see top of file).
5150+
// Ensure TEST_TMP exists so the file-sandbox / session tests can fopen /
5151+
// sqlite3_open inside it. EEXIST is fine; on Android the dir is already
5152+
// there (/data/local/tmp) and mkdir is a no-op.
5153+
adam_mkdir(TEST_TMP, 0755);
51455154

51465155
adam_init();
51475156
mem_report_start();

0 commit comments

Comments
 (0)