Skip to content

Instantly share code, notes, and snippets.

@archaelus
Created February 26, 2009 19:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save archaelus/71050 to your computer and use it in GitHub Desktop.
Save archaelus/71050 to your computer and use it in GitHub Desktop.
-module(rec_test).
-compile(export_all).
-include_lib("kernel/src/inet_dns.hrl").
%% Requires R12B5 +
-include_lib("eunit/include/eunit.hrl").
%% Retrieves the value stored in the record Rec in field Field.
info(Field, Rec) ->
Fields = fields(Rec),
info(Field, Fields, tl(tuple_to_list(Rec))).
info(_Field, _Fields, []) -> erlang:error(bad_record);
info(_Field, [], _Rec) -> erlang:error(bad_field);
info(Field, [Field | _], [Val | _]) -> Val;
info(Field, [_Other | Fields], [_Val | Values]) -> info(Field, Fields, Values).
%% The fields function provides the list of field positions
%% for all the kinds of record you want to be able to query
%% at runtime. You'll need to modify this to use your own records.
fields(#dns_rec{}) -> fields(dns_rec);
fields(dns_rec) -> record_info(fields, dns_rec);
fields(#dns_rr{}) -> fields(dns_rr);
fields(dns_rr) -> record_info(fields, dns_rr).
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ V || #RecordKind{MatchField=V} <- mnesia:table(RecordKind) ]
match(MatchField, RecordKind) ->
MatchTuple = match_tuple(MatchField, RecordKind),
{MatchTuple, [], ['$1']}.
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ T || T <- mnesia:table(RecordKind),
%% T#RecordKind.Field =:= MatchValue]
match(MatchField, MatchValue, RecordKind) ->
MatchTuple = match_tuple(MatchField, RecordKind),
{MatchTuple, [{'=:=', '$1', MatchValue}], ['$$']}.
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ T#RecordKind.ReturnField
%% || T <- mnesia:table(RecordKind),
%% T#RecordKind.MatchField =:= MatchValue]
match(MatchField, MatchValue, RecordKind, ReturnField)
when MatchField =/= ReturnField ->
MatchTuple = list_to_tuple([RecordKind
| [if F =:= MatchField -> '$1'; F =:= ReturnField -> '$2'; true -> '_' end
|| F <- fields(RecordKind)]]),
{MatchTuple, [{'=:=', '$1', MatchValue}], ['$2']}.
match_tuple(MatchField, RecordKind) ->
list_to_tuple([RecordKind
| [if F =:= MatchField -> '$1'; true -> '_' end
|| F <- fields(RecordKind)]]).
%% Turns a record into a proplist suitable for use with the proplists module.
to_proplist(R) ->
Keys = fields(R),
Values = tl(tuple_to_list(R)),
lists:zip(Keys,Values).
%% Eunit unit tests.
info_test_() ->
lists:flatten([info_test_(Rec) || Rec <- [dns_rr, dns_rec]]).
info_test_(Rec) ->
Fields = fields(Rec),
TestVal = list_to_tuple([Rec| Fields]),
[?_assertMatch(Field, (info(Field, TestVal)))
|| Field <- Fields].
match_test() ->
MS = ets:match_spec_compile([match(domain, dns_rr)]),
RRs = test_rrs(),
?assertMatch(["google.com", "google.com", "google.com",
"microsoft.com", "microsoft.com"],
(ets:match_spec_run(RRs, MS))).
match2_test() ->
MS = ets:match_spec_compile([match(domain, "google.com", dns_rr, data)]),
RRs = test_rrs(),
?assertMatch([{209, 85, 171, 100},{74, 125, 45, 100},{74, 125, 67, 100}],
(ets:match_spec_run(RRs, MS))).
test_rrs() ->
[{dns_rr, "google.com", in, a, 0, undefined, 231, [],
{209, 85, 171, 100},
false},
{dns_rr, "google.com", in, a, 0, undefined, 231, [],
{74, 125, 45, 100},
false},
{dns_rr, "google.com", in, a, 0, undefined, 231, [],
{74, 125, 67, 100},
false},
{dns_rr, "microsoft.com", in, a, 0, undefined, 2714, [],
{207, 46, 232, 182},
false},
{dns_rr, "microsoft.com", in, a, 0, undefined, 2714, [],
{207, 46, 197, 32},
false}].
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment