Skip to content

Commit

Permalink
Added propper and propper tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Licenser committed May 22, 2013
1 parent 1f76124 commit 70a84a9
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -33,7 +33,7 @@ xref:
$(REBAR) xref skip_deps=true

console: all
erl -pa ebin deps/*/ebin -s dhcp -config standalone.config
erl -pa ebin deps/*/ebin


##
Expand Down
3 changes: 2 additions & 1 deletion rebar.config
Expand Up @@ -2,5 +2,6 @@
{erl_opts, [{parse_transform, lager_transform}, debug_info, warnings_as_errors]}.
{deps,
[
{lager, ".*", {git, "git://github.com/basho/lager.git", {tag, "1.2.2"}}}
{lager, ".*", {git, "git://github.com/basho/lager.git", {tag, "1.2.2"}}},
{proper, ".*", {git, "git://github.com/manopapad/proper.git", {branch, master}}}
]}.
18 changes: 18 additions & 0 deletions src/dhcp.erl
Expand Up @@ -3,20 +3,36 @@
-include("dhcp.hrl").

-ifdef(TEST).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-endif.

-export([ip_to_tpl/1, tpl_to_ip/1]).

-spec ip_to_tpl(ip()) -> ip_tpl().

ip_to_tpl(I) when is_integer(I) ->
<<A:8, B:8, C:8, D:8>> = <<I:32>>,
{A, B, C, D}.

-spec tpl_to_ip(ip_tpl()) -> ip().

tpl_to_ip({A, B, C, D}) ->
<<I:32>> = <<A:8, B:8, C:8, D:8>>,
I.

-ifdef(TEST).

prop_ip_tpl_conversion() ->
?FORALL(Tpl, ip_tpl(),
begin
EncDecTpl = ip_to_tpl(tpl_to_ip(Tpl)),
EncDecTpl =:= Tpl
end).

propper_test() ->
?assertEqual([], proper:module(?MODULE, [{to_file, user}])).

ip2tpl_test() ->
?assertEqual({1,2,3,4}, ip_to_tpl(16#01020304)),
?assertEqual({0,0,0,0}, ip_to_tpl(16#00000000)),
Expand All @@ -26,5 +42,7 @@ tpl2ip_test() ->
?assertEqual(16#01020304, tpl_to_ip({1,2,3,4})),
?assertEqual(16#00000000, tpl_to_ip({0,0,0,0})),
?assertEqual(16#FFFFFFFF, tpl_to_ip({255,255,255,255})).


-endif.

190 changes: 175 additions & 15 deletions src/dhcp.hrl
@@ -1,26 +1,186 @@
-type message_type() ::
discover | offer | request | decline |
ack | nack | reelase | inform | force_renew.
ack | nck | release | inform | force_renew.

-type dhcp_op() :: request | reply.

-type mac() :: {pos_integer(),pos_integer(),pos_integer(),pos_integer(),pos_integer(),pos_integer()}.
-type octet() :: 0..255.
-type short() :: 0..65535.
-type mac() :: {octet(),octet(),octet(),octet(),octet(),octet()}.
-type ip() :: pos_integer().
-type ip_tpl() :: {octet(), octet(), octet(), octet()}.
-type flags() :: [broadcast] | [].

%-type zts() :: <<X:integer/8>> when X >=1.
-type null_terminated_string() :: binary().


-type htype() :: ethernet |
experiemental_ethernet |
ax25 |
proteon_token_ring |
chaos |
ieee802 |
arcnet |
hyperchannel |
lanstar |
autonet_short_address |
localtalk |
localnet |
ultra_link |
smds |
frame_relay |
atm16 |
hdlc |
fibre_channel |
atm19 |
serial_line |
atm21 |
mil_std_188_220 |
metricom |
ieee1394 |
mapos |
twinaxial |
eui64 |
hiparp |
ip_over_iso_7816_3 |
arpsec |
ipsec_tunnel |
infiniband |
cai_tia_102.

-type dhcp_option() :: {subnet_mask, ip()} |
{time_offset, pos_integer()} |
{router_address, [ip(),...]} |
{time_server, [ip(),...]} |
{ien_116_name_server, [ip(),...]} |
{domain_name_server, [ip(),...]} |
{log_server, [ip(),...]} |
{quotes_server, [ip(),...]} |
{lpr_server, [ip(),...]} |
{impress_server, [ip(),...]} |
{rlp_server, [ip(),...]} |
{hostname, binary()} |
{boot_file_size, short()} |
{merit_dump_file, binary()} |
{domain_name, binary()} |
{swap_server, ip()} |
{root_path, binary()} |
{bootp_extensions_path, binary()} |
{ip_forward_enable, byte()} |
{source_route_enable, byte()} |
{policy_filter, binary()} |
{max_datagram_reassembly_sz, short()} |
{default_ip_ttl, binary()} |
{path_mtu_aging_timeout, pos_integer()} |
{path_mtu_plateau_table, [short(), ...]} |
{interface_mtu_size, short()} |
{all_subnets_are_local, byte()} |
{broadcast_address, ip()} |
{perform_mask_discovery, byte()} |
{provide_mask_to_others, byte()} |
{perform_router_discovery, byte()} |
{router_solicitation_address, ip()} |
{static_routes, [ip(),...]} |
{trailer_encapsulation, byte()} |
{arp_cache_timeout, pos_integer()} |
{ethernet_encapsulation, byte()} |
{default_tcp_ttl, byte()} |
{keep_alive_interval, pos_integer()} |
{keep_alive_garbage, byte()} |
{nis_domain_name, binary()} |
{nis_servers, [ip(),...]} |
{ntp_servers, [ip(),...]} |
{vendor, binary()} |
{netbios_name_servers, [ip(),...]} |
{netbios_dgm_dist_servers, [ip(),...]} |
{netbios_node_type, byte()} |
{netbios, binary()} |
{x_window_font_server, [ip(),...]} |
{x_window_display_mgr, [ip(),...]} |
{requested_ip_address, ip()} |
{ip_address_lease_time, pos_integer()} |
{overload, byte()} |
{message_type, message_type()} |
{dhcp_server_identifier, ip()} |
{parameter_request_list, [byte(), ...]} |
{dhcp_error_message, binary()} |
{dhcp_maximum_msg_size, short()} |
{renewal_time, pos_integer()} |
{rebinding_time, pos_integer()} |
{vendor_class_identifier, binary()} |
{client_identifier, binary()} |
{netware_domain_name, binary()} |
{netware_sub_options, binary()} |
{nis_client_domain_name, binary()} |
{nis_server_address, ip()} |
{tftp_server_name, binary()} |
{boot_file_name, binary()} |
{home_agent_address, binary()} |
{smtp_server_address, [ip(),...]} |
{pop3_server_address, [ip(),...]} |
{nntp_server_address, [ip(),...]} |
{www_server_address, [ip(),...]} |
{finger_server_address, [ip(),...]} |
{irc_server_address, [ip(),...]} |
{streettalk_server_address, [ip(),...]} |
{stda_server_address, [ip(),...]} |
{user_class, binary()} |
{directory_agent, binary()} |
{service_scope, binary()} |
{rapid_commit, binary()} |
{client_fqdn, binary()} |
{relay_agent_information, binary()} |
{isns, binary()} |
{nds_servers, binary()} |
{nds_tree_name, binary()} |
{nds_context, binary()} |
{authentication, binary()} |
{client_last_txn_time, binary()} |
{associated_ip, binary()} |
{client_system, binary()} |
{client_ndi, binary()} |
{ldap, binary()} |
{uuid_guid, binary()} |
{user_auth, binary()} |
{netinfo_address, binary()} |
{netinfo_tag, binary()} |
{url, binary()} |
{auto_config, byte()} |
{name_service_search, binary()} |
{subnet_selection_option, binary()} |
{domain_search, binary()} |
{sip_servers_dhcp_option, binary()} |
{classless_static_route, binary()} |
{ccc, binary()} |
{geoconf_option, binary()} |
{v_i_vendor_class, binary()} |
{v_i_vendor_specific, binary()} |
{etherboot, binary()} |
{call_server_ip_address, binary()} |
{ethernet_interface, binary()} |
{remote_stats_svr_ip_address, binary()} |
{ieee_802_1q_l2_priority, binary()} |
{ieee_802_1p_vlan_id, binary()} |
{diffserv_code_point, binary()} |
{http_proxy, binary()} |
{cisco_tftp_server_ip_addresses, [ip(),...]}.

-record(dhcp_package,
{op = request :: dhcp_op(),
htype :: atom(),
hlen = 0 :: pos_integer(),
hops = 0 :: pos_integer(),
xid = 0 :: pos_integer(),
secs = 0 :: pos_integer(),
flags = [] :: [bradcast],
ciaddr = 0 :: pos_integer(),
yiaddr = 0 :: pos_integer(),
siaddr = 0 :: pos_integer(),
giaddr = 0 :: pos_integer(),
chaddr = {0,0,0,0,0,0}:: mac(),
htype = ethernet :: htype(),
hlen = 0 :: octet(),
hops = 0 :: octet(),
xid = 0 :: octet(),
secs = 0 :: octet(),
flags = [] :: flags(),
ciaddr = 0 :: ip(),
yiaddr = 0 :: ip(),
siaddr = 0 :: ip(),
giaddr = 0 :: ip(),
chaddr = {0,0,0,0,0,0} :: mac(),
sname = <<>> :: binary(),
file = <<>> :: binary(),
options = [] :: [{message_type, message_type()}|{atom(), binary()|integer()|[integer()]}],
message_type :: message_type()
options = [] :: [dhcp_option()],
message_type = ack :: message_type()
}).
75 changes: 68 additions & 7 deletions src/dhcp_package.erl
@@ -1,6 +1,7 @@
-module(dhcp_package).

-ifdef(TEST).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-endif.

Expand Down Expand Up @@ -369,7 +370,7 @@ decode_flags(<<0:1/integer, _:15>>) ->

encode_flags([]) ->
<<0:16/integer>>;
encode_flags([broadcast]) ->
encode_flags([broadcast|_]) ->
<<1:1/integer, 0:15/integer>>.

decode_ip(IP) ->
Expand Down Expand Up @@ -604,13 +605,13 @@ decode_option(Opt) ->
option_type(Opt) ->
opt(type, Opt).

decode_type(integer, <<L:8, I:L/integer-unit:8, R/binary>>) when L > 1 ->
decode_type(integer, <<L:8, I:L/integer-unit:8, R/binary>>) when L >= 1 ->
{I, R};
decode_type(octets, <<L:8, I:L/binary, R/binary>>) when L > 1 ->
decode_type(octets, <<L:8, I:L/binary, R/binary>>) when L >= 0 ->
{I, R};
decode_type(ipaddr, <<4:8, IP:32, R/binary>>) ->
{IP, R};
decode_type(ipaddrs, <<L:8, IPs:L/binary, R/binary>>) when L > 4,
decode_type(ipaddrs, <<L:8, IPs:L/binary, R/binary>>) when L >= 4,
L rem 4 =:= 0->
{[IP || <<IP:32>> <= IPs], R};
decode_type(byte, <<1:8, B:8, R/binary>>) ->
Expand All @@ -619,10 +620,10 @@ decode_type(bytes, <<L:8, Bs:L/binary, R/binary>>) ->
{[B || <<B:8>> <= Bs], R};
decode_type(short, <<2:8, S:16, R/binary>>) ->
{S, R};
decode_type(shorts, <<L:8, Ss:L/binary, R/binary>>) when L > 2,
decode_type(shorts, <<L:8, Ss:L/binary, R/binary>>) when L >= 2,
L rem 2 =:= 0->
{[S || <<S:16>> <= Ss], R};
decode_type(string, <<L:8, S:L/binary, R/binary>>) when L > 1 ->
decode_type(string, <<L:8, S:L/binary, R/binary>>) when L >= 0 ->
{S, R};
decode_type(message_type, <<1:8, T:8, R/binary>>) ->
{decode_message_type(T), R}.
Expand Down Expand Up @@ -662,7 +663,7 @@ encode_type(shorts, Ss) when is_list(Ss) ->
encode_type(string, S) when is_binary(S) ->
case byte_size(S) of
L when L =< 255,
L >= 1 ->
L >= 0 ->
<<L:8, S/binary>>
end;
encode_type(message_type, Type) ->
Expand Down Expand Up @@ -796,6 +797,66 @@ check_option(P, [], [Forbidden | R]) ->

-ifdef(TEST).


prop_mac_conversion() ->
?FORALL(Mac, mac(),
begin
EncDecMac = decode_mac(encode_mac(Mac)),
EncDecMac =:= Mac
end).

prop_ip_conversion() ->
?FORALL(IP, ip(),
begin
EncDecIP = decode_ip(encode_ip(IP)),
EncDecIP =:= IP
end).

prop_mt_conversion() ->
?FORALL(MT, message_type(),
begin
EncDecMT = decode_message_type(encode_message_type(MT)),
EncDecMT =:= MT
end).

prop_htype_conversion() ->
?FORALL(HType, htype(),
begin
EncDecHType = decode_htype(encode_htype(HType)),
EncDecHType =:= HType
end).


prop_string_conversion() ->
?FORALL(S, list(range(1,255)),
begin
BS = list_to_binary(S),
EncDecS = decode_string(encode_string(BS, byte_size(BS) + 2)),
EncDecS =:= BS
end).

prop_package_conversion() ->
?FORALL(P, package(),
begin
PMt = set_option(message_type, P#dhcp_package.message_type, P),
PMt1 = PMt#dhcp_package{
%% We need make sure options is sorted for compairison
options = lists:sort(PMt#dhcp_package.options),
%% We need to work around the fact that there is no notation for
%% lists with a exact number of elements
flags = ordsets:from_list(PMt#dhcp_package.flags),
%% There is no way to notate binarys that do not contain 0's
%% So we eliminate them and test the conversion sepperately
sname = <<>>,
file = <<>>},
{ok, EncP} = encode(PMt1),
{ok, EncDecP} = decode(EncP),
EncDecP =:= PMt1
end).

propper_test() ->
?assertEqual([], proper:module(?MODULE, [{to_file, user}])).

str_decode_test() ->
?assertEqual(<<"a">>, decode_string(<<"a", 0:8>>)),
?assertEqual(<<"a">>, decode_string(<<$a, 0:8, $c>>)),
Expand Down

0 comments on commit 70a84a9

Please sign in to comment.