shell-test.c 3.43 KB
Newer Older
Alexandru Dura's avatar
Alexandru Dura committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/wait.h>

int create_shell_process(char **argv, int *in, int *out) {
  int in_pipe[2];
  int out_pipe[2];

  if (pipe(in_pipe) < 0)
    return -1;

  if (pipe(out_pipe) < 0)
    return -1;

  int pid = fork();
  if (pid == 0) {
    // we're in the child

    // close the reading end of the out pipe
    close(out_pipe[0]);
    // close the writing end of the in pipe
    close(in_pipe[1]);
    // redirect stdout to the writing end of the out pipe
    dup2(out_pipe[1], STDOUT_FILENO);
    // redirect stdin to the reading end of the in pipe
    dup2(in_pipe[0], STDIN_FILENO);
    // now run the executable
    char *args[3] = {argv[0], argv[1], NULL};
    execv(argv[0], args);
  }

  if (pid < 0)
    return -1;

  // we're in the parent
  close(out_pipe[1]);
  close(in_pipe[0]);


  // configure the reads to be non-blocking
  int flags = fcntl(out_pipe[0], F_GETFL);
  fcntl(out_pipe[0], F_SETFL, flags | O_NONBLOCK);

  *in = in_pipe[1];
  *out = out_pipe[0];

  return pid;
}

int send_command(const char *cmd, char *result, size_t result_size, int sleep_sec, int in, int out) {
  memset(result, 0, result_size);
  int t0 = time(NULL);
  if (write(in, cmd, strlen(cmd)) < 0) {
    return -1;
  }
  if (sleep_sec) {
    // wait for the result
    sleep(sleep_sec);
  }
  read(out, result, result_size - 1);
  int t1 = time(NULL);
  return t1 - t0;
}



#define TEST_SLEEP(cmd, expected, sleep) do {					\
  printf("================================================================================\n");\
  printf(" RUN: %s", cmd); \
  int t = send_command(cmd, result_buf, sizeof(result_buf), sleep, in, out); \
  if (t < 0) { \
    printf("Error while sending commands to the shell."); \
  } \
Alexandru Dura's avatar
Alexandru Dura committed
80
81
82
83
  char *n = strchr(result_buf, '\n'); \
  if (n) {\
    *n = 0; \
  }\
Alexandru Dura's avatar
Alexandru Dura committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  if (strcmp(result_buf, expected)) {\
    ++n_fail;\
    printf("[FAIL] Expected '%s', but got '%s'.\n", expected, result_buf); \
  } else {\
    ++n_pass;\
    printf("[PASS]\n");\
  }\
  } while(0);

#define TEST(cmd, expected) \
  TEST_SLEEP(cmd, expected, 1)

int main(int argc, char **argv) {
  // create a temporary directory where to run the tests
  char tmp_dir_template[] = "test-dir-XXXXXX";
  char *tmp_dir = mkdtemp(tmp_dir_template);
  if (!chdir(tmp_dir)) {
    printf("Using test directory %s\n", tmp_dir);
  }
  char cwd[1000];
  getcwd(cwd, sizeof(cwd));

  // start the shell process
  int in, out;
  int shell_pid = create_shell_process(&argv[1], &in, &out);
  if (shell_pid < 0) {
    printf("Error launching the shell");
    exit(1);
  }

  // run the tests here
  char result_buf[1000];
  int n_pass = 0;
  int n_fail = 0;


  TEST("pwd\n", cwd);
  TEST("/bin/pwd\n", cwd);
  TEST("touch file1.txt\n", "");
  TEST("ls\n", "file1.txt");
  TEST_SLEEP("sleep 5; echo 'hello'\n", "hello", 6);
  TEST("sleep 5 & echo 'hello'\n", "hello");
  TEST("echo line1 > file1.txt\n", "");
  TEST("cat < file1.txt\n", "line1");
  TEST("cat file1.txt | wc -l\n", "1");
  TEST("cat file1.txt | cat | cat | cat | cat | wc -l\n", "1");
Alexandru Dura's avatar
Alexandru Dura committed
130
131
132
133
134
  TEST("mkdir dir1\n", "");
  TEST("cd dir1\n", "");
  TEST("ls\n", "");
  TEST("cd -\n", cwd);
  TEST("pwd\n", cwd);
Alexandru Dura's avatar
Alexandru Dura committed
135
136
137
138
139

  close(in);

  int wstatus;
  waitpid(shell_pid, &wstatus, 0);
Alexandru Dura's avatar
Alexandru Dura committed
140
141
  printf("================================================================================\n");
  printf("%d tests PASSED, %d tests FAILED.\n", n_pass, n_fail);
Alexandru Dura's avatar
Alexandru Dura committed
142
}