1 module unit_threaded.uda;
2 
3 import unit_threaded.meta;
4 import std.traits;
5 import std.meta;
6 
7 /**
8  * For the given module, return true if this module's member has
9  * the given UDA. UDAs can be types or values.
10  */
11 template HasAttribute(alias module_, string member, alias attribute) {
12     mixin(importMember!module_(member));
13 
14     static if(!__traits(compiles, __traits(getAttributes, mixin(member))))
15         enum HasAttribute = false;
16     else {
17         enum isAttribute(alias T) = is(TypeOf!T == attribute);
18         alias attrs = Filter!(isAttribute, __traits(getAttributes, mixin(member)));
19 
20         static assert(attrs.length == 0 || attrs.length == 1,
21                       text("Maximum number of attributes is 1 for ", attribute));
22 
23         static if(attrs.length == 0) {
24             enum HasAttribute = false;
25         } else {
26             enum HasAttribute = true;
27         }
28     }
29 }
30 
31 /**
32  * For the given module, return true if this module's member has
33  * the given UDA. UDAs can be types or values.
34  */
35 template GetAttributes(alias module_, string member, A) {
36     mixin(importMember!module_(member));
37     enum isAttribute(alias T) = is(TypeOf!T == A);
38     alias GetAttributes = Filter!(isAttribute, __traits(getAttributes, mixin(member)));
39 }
40 
41 
42 /**
43  * Utility to allow checking UDAs regardless of whether the template
44  * parameter is or has a type
45  */
46 private template TypeOf(alias T) {
47     static if(__traits(compiles, typeof(T))) {
48         alias TypeOf = typeof(T);
49     } else {
50         alias TypeOf = T;
51     }
52 }
53 
54 
55 
56 unittest {
57     import unit_threaded.attrs;
58     import unit_threaded.tests.module_with_attrs;
59 
60     //check for value UDAs
61     static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", HiddenTest));
62     static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", ShouldFail));
63     static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", Name));
64 
65     //check for non-value UDAs
66     static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", SingleThreaded));
67     static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", DontTest));
68 
69     static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testValues", ShouldFail));
70 }
71 
72 template isTypesAttr(alias T) {
73     import unit_threaded.attrs;
74     enum isTypesAttr = is(T) && is(T:Types!U, U...);
75 }
76 
77 
78 /*
79  @Types is different from the other UDAs since it's a templated struct
80  None of the templates above work so we special case it here
81 */
82 
83 /// If a test has the @Types UDA
84 enum HasTypes(alias T) = GetTypes!T.length > 0;
85 
86 /// Returns the types in the @Types UDA associated to a test
87 template GetTypes(alias T) {
88     static if(!__traits(compiles, __traits(getAttributes, T))) {
89         alias GetTypes = AliasSeq!();
90     } else {
91         alias types = Filter!(isTypesAttr, __traits(getAttributes, T));
92         static if(types.length > 0)
93             alias GetTypes = TemplateArgsOf!(types[0]);
94         else
95             alias GetTypes = AliasSeq!();
96     }
97 }
98 
99 
100 ///
101 unittest {
102     import unit_threaded.attrs;
103     @Types!(int, float) int i;
104     static assert(HasTypes!i);
105     static assert(is(GetTypes!i == AliasSeq!(int, float)));
106 
107 }