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 import std.traits: hasUDA; 60 61 //check for value UDAs 62 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", HiddenTest)); 63 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", ShouldFail)); 64 static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", Name)); 65 66 //check for non-value UDAs 67 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", SingleThreaded)); 68 static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", DontTest)); 69 70 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testValues", ShouldFail)); 71 } 72 73 template isTypesAttr(alias T) { 74 import unit_threaded.attrs; 75 enum isTypesAttr = is(T) && is(T:Types!U, U...); 76 } 77 78 79 /* 80 @Types is different from the other UDAs since it's a templated struct 81 None of the templates above work so we special case it here 82 */ 83 84 /// If a test has the @Types UDA 85 enum HasTypes(alias T) = GetTypes!T.length > 0; 86 87 /// Returns the types in the @Types UDA associated to a test 88 template GetTypes(alias T) { 89 static if(!__traits(compiles, __traits(getAttributes, T))) { 90 alias GetTypes = AliasSeq!(); 91 } else { 92 alias types = Filter!(isTypesAttr, __traits(getAttributes, T)); 93 static if(types.length > 0) 94 alias GetTypes = TemplateArgsOf!(types[0]); 95 else 96 alias GetTypes = AliasSeq!(); 97 } 98 } 99 100 101 /// 102 unittest { 103 import unit_threaded.attrs; 104 @Types!(int, float) int i; 105 static assert(HasTypes!i); 106 static assert(is(GetTypes!i == AliasSeq!(int, float))); 107 108 } 109 110 // copy of recent hasUDA from Phobos here because old 111 // compilers will fail otherwise 112 113 enum hasUtUDA(alias symbol, alias attribute) = getUtUDAs!(symbol, attribute).length > 0; 114 115 template getUtUDAs(alias symbol, alias attribute) 116 { 117 import std.meta : Filter; 118 119 template isDesiredUDA(alias toCheck) 120 { 121 static if (is(typeof(attribute)) && !__traits(isTemplate, attribute)) 122 { 123 static if (__traits(compiles, toCheck == attribute)) 124 enum isDesiredUDA = toCheck == attribute; 125 else 126 enum isDesiredUDA = false; 127 } 128 else static if (is(typeof(toCheck))) 129 { 130 static if (__traits(isTemplate, attribute)) 131 enum isDesiredUDA = isInstanceOf!(attribute, typeof(toCheck)); 132 else 133 enum isDesiredUDA = is(typeof(toCheck) == attribute); 134 } 135 else static if (__traits(isTemplate, attribute)) 136 enum isDesiredUDA = isInstanceOf!(attribute, toCheck); 137 else 138 enum isDesiredUDA = is(toCheck == attribute); 139 } 140 141 alias getUtUDAs = Filter!(isDesiredUDA, __traits(getAttributes, symbol)); 142 } 143 144 unittest { 145 import unit_threaded.attrs; 146 import unit_threaded.tests.module_with_attrs; 147 import std.traits: hasUDA; 148 149 static assert(hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith)); 150 static assert(hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith!Exception)); 151 static assert(!hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith!Throwable)); 152 }