Skip to content

Commit 156a2b7

Browse files
committed
Tests and bug fixes
1 parent 8d9b55c commit 156a2b7

File tree

5 files changed

+146
-10
lines changed

5 files changed

+146
-10
lines changed

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
source 'https://rubygems.org'
22
gem 'github-pages', group: :jekyll_plugins
33
gem "jekyll-theme-minimal"
4+
gem "rspec"

Gemfile.lock

+15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ GEM
1313
execjs
1414
coffee-script-source (1.12.2)
1515
colorator (1.1.0)
16+
diff-lcs (1.3)
1617
ethon (0.10.1)
1718
ffi (>= 1.3.0)
1819
execjs (2.7.0)
@@ -189,6 +190,19 @@ GEM
189190
rb-inotify (0.9.10)
190191
ffi (>= 0.5.0, < 2)
191192
rouge (1.11.1)
193+
rspec (3.6.0)
194+
rspec-core (~> 3.6.0)
195+
rspec-expectations (~> 3.6.0)
196+
rspec-mocks (~> 3.6.0)
197+
rspec-core (3.6.0)
198+
rspec-support (~> 3.6.0)
199+
rspec-expectations (3.6.0)
200+
diff-lcs (>= 1.2.0, < 2.0)
201+
rspec-support (~> 3.6.0)
202+
rspec-mocks (3.6.0)
203+
diff-lcs (>= 1.2.0, < 2.0)
204+
rspec-support (~> 3.6.0)
205+
rspec-support (3.6.0)
192206
safe_yaml (1.0.4)
193207
sass (3.5.1)
194208
sass-listen (~> 4.0.0)
@@ -213,6 +227,7 @@ PLATFORMS
213227
DEPENDENCIES
214228
github-pages
215229
jekyll-theme-minimal
230+
rspec
216231

217232
BUNDLED WITH
218233
1.15.3

Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ run: db
77
clean:
88
rm -f db *.db
99

10+
test: db
11+
bundle exec rspec
12+
1013
format: *.c
1114
clang-format -style=Google -i *.c

db.c

+41-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ typedef enum MetaCommandResult_t MetaCommandResult;
2121

2222
enum PrepareResult_t {
2323
PREPARE_SUCCESS,
24+
PREPARE_NEGATIVE_ID,
25+
PREPARE_STRING_TOO_LONG,
2426
PREPARE_SYNTAX_ERROR,
2527
PREPARE_UNRECOGNIZED_STATEMENT
2628
};
@@ -33,8 +35,8 @@ const uint32_t COLUMN_USERNAME_SIZE = 32;
3335
const uint32_t COLUMN_EMAIL_SIZE = 255;
3436
struct Row_t {
3537
uint32_t id;
36-
char username[COLUMN_USERNAME_SIZE];
37-
char email[COLUMN_EMAIL_SIZE];
38+
char username[COLUMN_USERNAME_SIZE + 1];
39+
char email[COLUMN_EMAIL_SIZE + 1];
3840
};
3941
typedef struct Row_t Row;
4042

@@ -133,17 +135,40 @@ MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
133135
}
134136
}
135137

138+
PrepareResult prepare_insert(InputBuffer* input_buffer, Statement* statement) {
139+
statement->type = STATEMENT_INSERT;
140+
141+
char* keyword = strtok(input_buffer->buffer, " ");
142+
char* id_string = strtok(NULL, " ");
143+
char* username = strtok(NULL, " ");
144+
char* email = strtok(NULL, " ");
145+
146+
if (id_string == NULL || username == NULL || email == NULL) {
147+
return PREPARE_SYNTAX_ERROR;
148+
}
149+
150+
int id = atoi(id_string);
151+
if (id < 0) {
152+
return PREPARE_NEGATIVE_ID;
153+
}
154+
if (strlen(username) > COLUMN_USERNAME_SIZE) {
155+
return PREPARE_STRING_TOO_LONG;
156+
}
157+
if (strlen(email) > COLUMN_EMAIL_SIZE) {
158+
return PREPARE_STRING_TOO_LONG;
159+
}
160+
161+
statement->row_to_insert.id = id;
162+
strcpy(statement->row_to_insert.username, username);
163+
strcpy(statement->row_to_insert.email, email);
164+
165+
return PREPARE_SUCCESS;
166+
}
167+
136168
PrepareResult prepare_statement(InputBuffer* input_buffer,
137169
Statement* statement) {
138170
if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
139-
statement->type = STATEMENT_INSERT;
140-
int args_assigned = sscanf(
141-
input_buffer->buffer, "insert %d %s %s", &(statement->row_to_insert.id),
142-
statement->row_to_insert.username, statement->row_to_insert.email);
143-
if (args_assigned < 3) {
144-
return PREPARE_SYNTAX_ERROR;
145-
}
146-
return PREPARE_SUCCESS;
171+
return prepare_insert(input_buffer, statement);
147172
}
148173
if (strcmp(input_buffer->buffer, "select") == 0) {
149174
statement->type = STATEMENT_SELECT;
@@ -205,6 +230,12 @@ int main(int argc, char* argv[]) {
205230
switch (prepare_statement(input_buffer, &statement)) {
206231
case (PREPARE_SUCCESS):
207232
break;
233+
case (PREPARE_NEGATIVE_ID):
234+
printf("ID must be positive.\n");
235+
continue;
236+
case (PREPARE_STRING_TOO_LONG):
237+
printf("String is too long.\n");
238+
continue;
208239
case (PREPARE_SYNTAX_ERROR):
209240
printf("Syntax error. Could not parse statement.\n");
210241
continue;

spec/main_spec.rb

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
describe 'database' do
2+
def run_script(commands)
3+
raw_output = nil
4+
IO.popen("./db", "r+") do |pipe|
5+
commands.each do |command|
6+
pipe.puts command
7+
end
8+
9+
pipe.close_write
10+
11+
# Read entire output
12+
raw_output = pipe.gets(nil)
13+
end
14+
raw_output.split("\n")
15+
end
16+
17+
it 'inserts and retreives a row' do
18+
result = run_script([
19+
"insert 1 user1 [email protected]",
20+
"select",
21+
".exit",
22+
])
23+
expect(result).to eq([
24+
"db > Executed.",
25+
"db > (1, user1, [email protected])",
26+
"Executed.",
27+
"db > ",
28+
])
29+
end
30+
31+
it 'prints error message when table is full' do
32+
script = (1..1401).map do |i|
33+
"insert #{i} user#{i} person#{i}@example.com"
34+
end
35+
script << ".exit"
36+
result = run_script(script)
37+
expect(result[-2]).to eq('db > Error: Table full.')
38+
end
39+
40+
it 'allows inserting strings that are the maximum length' do
41+
long_username = "a"*32
42+
long_email = "a"*255
43+
script = [
44+
"insert 1 #{long_username} #{long_email}",
45+
"select",
46+
".exit",
47+
]
48+
result = run_script(script)
49+
expect(result).to eq([
50+
"db > Executed.",
51+
"db > (1, #{long_username}, #{long_email})",
52+
"Executed.",
53+
"db > ",
54+
])
55+
end
56+
57+
it 'prints error message if strings are too long' do
58+
long_username = "a"*33
59+
long_email = "a"*256
60+
script = [
61+
"insert 1 #{long_username} #{long_email}",
62+
"select",
63+
".exit",
64+
]
65+
result = run_script(script)
66+
expect(result).to eq([
67+
"db > String is too long.",
68+
"db > Executed.",
69+
"db > ",
70+
])
71+
end
72+
73+
it 'prints an error message if id is negative' do
74+
script = [
75+
"insert -1 cstack [email protected]",
76+
"select",
77+
".exit",
78+
]
79+
result = run_script(script)
80+
expect(result).to eq([
81+
"db > ID must be positive.",
82+
"db > Executed.",
83+
"db > ",
84+
])
85+
end
86+
end

0 commit comments

Comments
 (0)