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 }