Fix message.
[pintos-anon] / src / tests / lib.c
1 #include "tests/lib.h"
2 #include <random.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <syscall.h>
7
8 const char *test_name;
9 bool quiet = false;
10
11 static void
12 vmsg (const char *format, va_list args, const char *suffix) 
13 {
14   /* We go to some trouble to stuff the entire message into a
15      single buffer and output it in a single system call, because
16      that'll (typically) ensure that it gets sent to the console
17      atomically.  Otherwise kernel messages like "foo: exit(0)"
18      can end up being interleaved if we're unlucky. */
19   static char buf[1024];
20
21   snprintf (buf, sizeof buf, "(%s) ", test_name);
22   vsnprintf (buf + strlen (buf), sizeof buf - strlen (buf), format, args);
23   strlcpy (buf + strlen (buf), suffix, sizeof buf - strlen (buf));
24   write (STDOUT_FILENO, buf, strlen (buf));
25 }
26
27 void
28 msg (const char *format, ...) 
29 {
30   va_list args;
31
32   if (quiet)
33     return;
34   va_start (args, format);
35   vmsg (format, args, "\n");
36   va_end (args);
37 }
38
39 void
40 fail (const char *format, ...) 
41 {
42   va_list args;
43
44   va_start (args, format);
45   vmsg (format, args, ": FAILED\n");
46   va_end (args);
47
48   exit (1);
49 }
50
51 static void
52 swap (void *a_, void *b_, size_t size) 
53 {
54   uint8_t *a = a_;
55   uint8_t *b = b_;
56   size_t i;
57
58   for (i = 0; i < size; i++) 
59     {
60       uint8_t t = a[i];
61       a[i] = b[i];
62       b[i] = t;
63     }
64 }
65
66 void
67 shuffle (void *buf_, size_t cnt, size_t size) 
68 {
69   char *buf = buf_;
70   size_t i;
71
72   for (i = 0; i < cnt; i++)
73     {
74       size_t j = i + random_ulong () % (cnt - i);
75       swap (buf + i * size, buf + j * size, size);
76     }
77 }
78
79 void
80 exec_children (const char *child_name, pid_t pids[], size_t child_cnt) 
81 {
82   size_t i;
83
84   for (i = 0; i < child_cnt; i++) 
85     {
86       char cmd_line[128];
87       snprintf (cmd_line, sizeof cmd_line, "%s %zu", child_name, i);
88       CHECK ((pids[i] = exec (cmd_line)) != PID_ERROR,
89              "exec child %zu of %zu: \"%s\"", i + 1, child_cnt, cmd_line);
90     }
91 }
92
93 void
94 wait_children (pid_t pids[], size_t child_cnt) 
95 {
96   size_t i;
97   
98   for (i = 0; i < child_cnt; i++) 
99     {
100       int status = wait (pids[i]);
101       CHECK (status == (int) i,
102              "wait for child %zu of %zu returned %d (expected %zu)",
103              i + 1, child_cnt, status, i);
104     }
105 }
106
107 void
108 check_file_handle (int fd,
109                    const char *file_name, const void *buf_, size_t size) 
110 {
111   const char *buf = buf_;
112   size_t ofs = 0;
113   size_t file_size;
114
115   /* Warn about file of wrong size.  Don't fail yet because we
116      may still be able to get more information by reading the
117      file. */
118   file_size = filesize (fd);
119   if (file_size != size)
120     msg ("size of %s (%zu) differs from expected (%zu)",
121           file_name, file_size, size);
122
123   /* Read the file block-by-block, comparing data as we go. */
124   while (ofs < size)
125     {
126       char block[512];
127       size_t block_size, ret_val;
128
129       block_size = size - ofs;
130       if (block_size > sizeof block)
131         block_size = sizeof block;
132
133       ret_val = read (fd, block, block_size);
134       if (ret_val != block_size)
135         fail ("read of %zu bytes at offset %zu in \"%s\" returned %zu",
136               block_size, ofs, file_name, ret_val);
137
138       compare_bytes (block, buf + ofs, block_size, ofs, file_name);
139       ofs += block_size;
140     }
141
142   /* Now fail due to wrong file size. */
143   if (file_size != size)
144     fail ("size of %s (%zu) differs from expected (%zu)",
145           file_name, file_size, size);
146
147   msg ("verified contents of \"%s\"", file_name);
148 }
149
150 void
151 check_file (const char *file_name, const void *buf, size_t size) 
152 {
153   int fd;
154
155   CHECK ((fd = open (file_name)) > 1, "open \"%s\" for verification",
156          file_name);
157   check_file_handle (fd, file_name, buf, size);
158   msg ("close \"%s\"", file_name);
159   close (fd);
160 }
161
162 void
163 compare_bytes (const void *read_data_, const void *expected_data_, size_t size,
164                size_t ofs, const char *file_name) 
165 {
166   const uint8_t *read_data = read_data_;
167   const uint8_t *expected_data = expected_data_;
168   size_t i, j;
169   size_t show_cnt;
170
171   if (!memcmp (read_data, expected_data, size))
172     return;
173   
174   for (i = 0; i < size; i++)
175     if (read_data[i] != expected_data[i])
176       break;
177   for (j = i + 1; j < size; j++)
178     if (read_data[j] == expected_data[j])
179       break;
180
181   quiet = false;
182   msg ("%zu bytes read starting at offset %zu in \"%s\" differ "
183        "from expected.", j - i, ofs + i, file_name);
184   show_cnt = j - i;
185   if (j - i > 64) 
186     {
187       show_cnt = 64;
188       msg ("Showing first differing %zu bytes.", show_cnt);
189     }
190   msg ("Data actually read:");
191   hex_dump (ofs + i, read_data + i, show_cnt, true);
192   msg ("Expected data:");
193   hex_dump (ofs + i, expected_data + i, show_cnt, true);
194   fail ("%zu bytes read starting at offset %zu in \"%s\" differ "
195         "from expected", j - i, ofs + i, file_name);
196 }