1 module unit_threaded.uda; 2 3 /** 4 * For the given module, return true if this module's member has 5 * the given UDA. UDAs can be types or values. 6 */ 7 template HasAttribute(alias module_, string member, alias attribute) { 8 import unit_threaded.meta: importMember; 9 import std.meta: Filter; 10 11 mixin(importMember!module_(member)); 12 13 static if(!__traits(compiles, __traits(getAttributes, mixin(member)))) 14 enum HasAttribute = false; 15 else { 16 enum isAttribute(alias T) = is(TypeOf!T == attribute); 17 alias attrs = Filter!(isAttribute, __traits(getAttributes, mixin(member))); 18 19 static assert(attrs.length == 0 || attrs.length == 1, 20 text("Maximum number of attributes is 1 for ", attribute)); 21 22 static if(attrs.length == 0) { 23 enum HasAttribute = false; 24 } else { 25 enum HasAttribute = true; 26 } 27 } 28 } 29 30 /** 31 * For the given module, return true if this module's member has 32 * the given UDA. UDAs can be types or values. 33 */ 34 template GetAttributes(alias module_, string member, A) { 35 import unit_threaded.meta: importMember; 36 import std.meta: Filter; 37 38 mixin(importMember!module_(member)); 39 enum isAttribute(alias T) = is(TypeOf!T == A); 40 alias GetAttributes = Filter!(isAttribute, __traits(getAttributes, mixin(member))); 41 } 42 43 44 /** 45 * Utility to allow checking UDAs regardless of whether the template 46 * parameter is or has a type 47 */ 48 private template TypeOf(alias T) { 49 static if(__traits(compiles, typeof(T))) { 50 alias TypeOf = typeof(T); 51 } else { 52 alias TypeOf = T; 53 } 54 } 55 56 57 58 unittest { 59 import unit_threaded.attrs; 60 import unit_threaded.tests.module_with_attrs; 61 import std.traits: hasUDA; 62 63 //check for value UDAs 64 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", HiddenTest)); 65 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", ShouldFail)); 66 static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", Name)); 67 68 //check for non-value UDAs 69 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", SingleThreaded)); 70 static assert(!HasAttribute!(unit_threaded.tests.module_with_attrs, "testAttrs", DontTest)); 71 72 static assert(HasAttribute!(unit_threaded.tests.module_with_attrs, "testValues", ShouldFail)); 73 } 74 75 template isTypesAttr(alias T) { 76 import unit_threaded.attrs; 77 enum isTypesAttr = is(T) && is(T:Types!U, U...); 78 } 79 80 81 /* 82 @Types is different from the other UDAs since it's a templated struct 83 None of the templates above work so we special case it here 84 */ 85 86 /// If a test has the @Types UDA 87 enum HasTypes(alias T) = GetTypes!T.length > 0; 88 89 /// Returns the types in the @Types UDA associated to a test 90 template GetTypes(alias T) { 91 import std.meta: Filter, AliasSeq; 92 import std.traits: TemplateArgsOf; 93 94 static if(!__traits(compiles, __traits(getAttributes, T))) { 95 alias GetTypes = AliasSeq!(); 96 } else { 97 alias types = Filter!(isTypesAttr, __traits(getAttributes, T)); 98 static if(types.length > 0) 99 alias GetTypes = TemplateArgsOf!(types[0]); 100 else 101 alias GetTypes = AliasSeq!(); 102 } 103 } 104 105 106 /// 107 unittest { 108 import unit_threaded.attrs; 109 import std.meta; 110 111 @Types!(int, float) int i; 112 static assert(HasTypes!i); 113 static assert(is(GetTypes!i == AliasSeq!(int, float))); 114 115 } 116 117 // copy of recent hasUDA from Phobos here because old 118 // compilers will fail otherwise 119 120 enum hasUtUDA(alias symbol, alias attribute) = getUtUDAs!(symbol, attribute).length > 0; 121 122 template getUtUDAs(alias symbol, alias attribute) 123 { 124 import std.meta : Filter; 125 import std.traits: isInstanceOf; 126 127 template isDesiredUDA(alias toCheck) 128 { 129 static if (is(typeof(attribute)) && !__traits(isTemplate, attribute)) 130 { 131 static if (__traits(compiles, toCheck == attribute)) 132 enum isDesiredUDA = toCheck == attribute; 133 else 134 enum isDesiredUDA = false; 135 } 136 else static if (is(typeof(toCheck))) 137 { 138 static if (__traits(isTemplate, attribute)) 139 enum isDesiredUDA = isInstanceOf!(attribute, typeof(toCheck)); 140 else 141 enum isDesiredUDA = is(typeof(toCheck) == attribute); 142 } 143 else static if (__traits(isTemplate, attribute)) 144 enum isDesiredUDA = isInstanceOf!(attribute, toCheck); 145 else 146 enum isDesiredUDA = is(toCheck == attribute); 147 } 148 149 alias getUtUDAs = Filter!(isDesiredUDA, __traits(getAttributes, symbol)); 150 } 151 152 unittest { 153 import unit_threaded.attrs; 154 import unit_threaded.tests.module_with_attrs; 155 import std.traits: hasUDA; 156 157 static assert(hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith)); 158 static assert(hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith!Exception)); 159 static assert(!hasUtUDA!(unit_threaded.tests.module_with_attrs.testOtherAttrs, ShouldFailWith!Throwable)); 160 }