Added EUnit tests

This commit is contained in:
Alexey Romanov
2010-10-12 16:42:57 +04:00
parent 27720f493e
commit 972df93fbb
3 changed files with 135 additions and 30 deletions

View File

@@ -485,9 +485,13 @@ handle_call({table_info, Tbl}, _From, #state{port = Port} = State) ->
SQL = io_lib:format("select sql from sqlite_master where tbl_name = '~p' and type='table';", [Tbl]),
Data = exec(Port, {sql_exec, SQL}),
TableSql = proplists:get_value(rows, Data),
[{Info}] = TableSql,
ColumnList = parse_table_info(binary_to_list(Info)),
{reply, ColumnList, State};
case TableSql of
[{Info}] ->
ColumnList = parse_table_info(binary_to_list(Info)),
{reply, ColumnList, State};
[] ->
{reply, table_does_not_exist, State}
end;
handle_call({create_function, FunctionName, Function}, _From, #state{port = Port} = State) ->
% make sure we only get table info.
% SQL Injection warning
@@ -630,15 +634,29 @@ build_table_info([[ColName, ColType | Constraints] | Tl], Acc) ->
%% TODO conflict-clause parsing
build_constraints([]) -> [];
build_constraints(["PRIMARY", "KEY", "ASC" | Tail]) -> [primary_key | build_constraints(Tail)];
build_constraints(["PRIMARY", "KEY", "DESC" | Tail]) -> [{primary_key, desc} | build_constraints(Tail)];
build_constraints(["PRIMARY", "KEY" | Tail]) -> [primary_key | build_constraints(Tail)];
build_constraints(["PRIMARY", "KEY" | Tail]) ->
{Constraint, Rest} = build_primary_key_constraint(Tail),
[Constraint | build_constraints(Rest)];
build_constraints(["UNIQUE" | Tail]) -> [unique | build_constraints(Tail)];
build_constraints(["NOT", "NULL" | Tail]) -> [not_null | build_constraints(Tail)];
build_constraints(["DEFAULT", DefaultValue | Tail]) -> [{default, sqlite3_lib:sql_to_value(DefaultValue)} | build_constraints(Tail)].
% build_constraints(["CHECK", Check | Tail]) -> ...
% build_constraints(["REFERENCES", Check | Tail]) -> ...
build_primary_key_constraint(Tokens) -> build_primary_key_constraint(Tokens, []).
build_primary_key_constraint(["ASC" | Rest], Acc) ->
build_primary_key_constraint(Rest, [asc | Acc]);
build_primary_key_constraint(["DESC" | Rest], Acc) ->
build_primary_key_constraint(Rest, [desc | Acc]);
build_primary_key_constraint(["AUTOINCREMENT" | Rest], Acc) ->
build_primary_key_constraint(Rest, [autoincrement | Acc]);
build_primary_key_constraint(Tail, []) ->
{primary_key, Tail};
build_primary_key_constraint(Tail, Acc) ->
{{primary_key, lists:reverse(Acc)}, Tail}.
conflict_clause(["ON", "CONFLICT", ResolutionString | Tail]) ->
Resolution = case ResolutionString of
"ROLLBACK" -> rollback;
@@ -658,3 +676,11 @@ conflict_clause(NoOnConflictClause) ->
%% and io:iolist().
%% @end
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Tests
%%--------------------------------------------------------------------
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

View File

@@ -116,14 +116,14 @@ sql_to_value(String) ->
end.
%%--------------------------------------------------------------------
%% @spec write_value_sql(Value :: [term()]) -> iolist()
%% @spec write_value_sql(Value :: [sql_value()]) -> iolist()
%% @doc
%% Creates the values portion of the sql stmt.
%% @end
%%--------------------------------------------------------------------
-spec write_value_sql(any()) -> iolist().
-spec write_value_sql(sql_value()) -> iolist().
write_value_sql(Values) ->
map_intersperse(fun value_to_sql/1, Values, ",").
map_intersperse(fun value_to_sql/1, Values, ", ").
%%--------------------------------------------------------------------
@@ -133,7 +133,7 @@ write_value_sql(Values) ->
%%--------------------------------------------------------------------
-spec write_col_sql([atom()]) -> iolist().
write_col_sql(Cols) ->
map_intersperse(fun atom_to_list/1, Cols, ",").
map_intersperse(fun atom_to_list/1, Cols, ", ").
%%--------------------------------------------------------------------
%% @spec escape(IoData :: iodata()) -> iodata()
@@ -355,3 +355,18 @@ indexed_column_sql(ColumnName) -> atom_to_list(ColumnName).
%% and io:iolist().
%% @end
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Tests
%%--------------------------------------------------------------------
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-define(FLAT(X), iolist_to_binary(X)).
quote_test() ->
?assertEqual(<<"'abc'">>, ?FLAT(value_to_sql("abc"))),
?assertEqual(<<"'a''b''''c'">>, ?FLAT(value_to_sql("a'b''c"))).
-endif.

View File

@@ -17,26 +17,90 @@
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
create_table_test() ->
file:delete("ct.db"),
sqlite3:open(ct),
sqlite3:create_table(ct, user, [{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}]),
[user] = sqlite3:list_tables(ct),
[{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}] = sqlite3:table_info(ct, user),
{id, Id1} = sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}]),
Id1 = 1,
{id, Id2} = sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}]),
Id2 = 2,
[{columns, Columns}, {rows, Rows1}] = sqlite3:sql_exec(ct, "select * from user;"),
drop_all_tables(Db) ->
Tables = sqlite3:list_tables(Db),
[sqlite3:drop_table(Db, Table) || Table <- Tables],
Tables.
drop_table_if_exists(Db, Table) ->
case lists:member(Table, sqlite3:list_tables(Db)) of
true -> sqlite3:drop_table(Db, Table);
false -> ok
end.
rows(SqlExecReply) ->
[{columns, _Columns}, {rows, Rows}] = SqlExecReply,
Rows.
basic_functionality_test() ->
Columns = ["id", "name", "age", "wage"],
Rows1 = [{1, <<"abby">>, 20, 2000}, {2, <<"marge">>, 30, 2000}],
[{columns, Columns}, {rows, Rows2}] = sqlite3:read(ct, user, {name, "abby"}),
Rows2 = [{1, <<"abby">>, 20, 2000}],
[{columns, Columns}, {rows, Rows1}] = sqlite3:read(ct, user, {wage, 2000}),
sqlite3:delete(ct, user, {name, "abby"}),
sqlite3:drop_table(ct, user),
%sqlite3:delete_db(ct)
sqlite3:close(ct).
AllRows = [{1, <<"abby">>, 20, 2000}, {2, <<"marge">>, 30, 2000}],
AbbyOnly = [{1, <<"abby">>, 20, 2000}],
sqlite3:open(ct),
drop_all_tables(ct),
?assertEqual(
[],
sqlite3:list_tables(ct)),
{ok, TableId} = sqlite3:create_table(ct, user, [{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}]),
?assertEqual(
[user],
sqlite3:list_tables(ct)),
?assertEqual(
[{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}],
sqlite3:table_info(ct, user)),
?assertEqual(
{id, 1},
sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}])),
?assertEqual(
{id, 2},
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
?assertEqual(
[{columns, Columns}, {rows, AllRows}],
sqlite3:sql_exec(ct, "select * from user;")),
?assertEqual(
[{columns, Columns}, {rows, AbbyOnly}],
sqlite3:read(ct, user, {name, "abby"})),
?assertEqual(
[{columns, Columns}, {rows, AllRows}],
sqlite3:read(ct, user, {wage, 2000})),
?assertEqual(
{ok, TableId},
sqlite3:delete(ct, user, {name, "marge"})),
?assertEqual(
[{columns, Columns}, {rows, AbbyOnly}],
sqlite3:sql_exec(ct, "select * from user;")),
?assertEqual(
{ok, TableId},
sqlite3:drop_table(ct, user)),
sqlite3:close(ct).
select_many_records_test() ->
sqlite3:open(ct),
drop_table_if_exists(ct, many_records),
sqlite3:create_table(ct, many_records, [{id, integer}, {name, text}]),
lists:foreach(fun(X) -> sqlite3:write(ct, many_records, [{id, X}, {name, "bar"}]) end, lists:seq(1, 1024)),
Columns = ["id", "name"],
?assertEqual(
[{columns, Columns}, {rows, [{1, <<"bar">>}]}],
sqlite3:read(ct, many_records, {id, 1})),
?assertEqual(
10,
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 10;")))),
?assertEqual(
100,
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 100;")))),
?assertEqual(
1000,
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 1000;")))),
?assertEqual(
1024,
length(rows(sqlite3:sql_exec(ct, "select * from many_records;")))),
sqlite3:close(ct).
nonexistent_table_info_test() ->
sqlite3:open(ct),
?assertEqual(table_does_not_exist, sqlite3:table_info(ct, nonexistent)),
sqlite3:close(ct).
-endif.