1 module tests.expressions; 2 3 private 4 { 5 import std.conv : to; 6 7 import tests.asserts; 8 } 9 10 // Literals 11 unittest 12 { 13 // True/False 14 assertRender("{{ true }}", "true"); 15 assertRender("{{ True }}", "true"); 16 assertRender("{{ false }}", "false"); 17 assertRender("{{ False }}", "false"); 18 19 // Numbers 20 assertRender("{{ 10 }}", "10"); 21 assertRender("{{ 10.5 }}", (10.5).to!string); 22 assertRender("{{ -10 }}", "-10"); 23 assertRender("{{ -10.5 }}", (-10.5).to!string); 24 25 // String 26 assertRender("{{ 'some string' }}", "some string"); 27 assertRender(`{{ "some string" }}`, "some string"); 28 29 // List 30 assertRender("{{ [] }}", "[]"); 31 assertRender("{{ [1,2,3] }}", "[1, 2, 3]"); 32 33 // Tuple (also list actually) 34 assertRender("{{ (1,2,3) }}", "[1, 2, 3]"); 35 assertRender("{{ (1,)}}", "[1]"); 36 37 // Dict 38 assertRender("{{ {} }}", "{}"); 39 assertRender(`{{ {a:10} }}`, "{a: 10}"); 40 // can't check print of more than one key due to undefined order: 41 assertRender(`{{ {a:True, 'b':10, "c":"string"} | sort }}`, 42 "[['a', true], ['b', 10], ['c', 'string']]"); 43 44 // Idents 45 struct Dummy 46 { 47 string str; 48 int[] arr; 49 ubyte idx; 50 } 51 auto val = Dummy("some string", [1,2,3], 2); 52 53 assertRender!(val)("{{ val | sort }}", "[['arr', [1, 2, 3]], ['idx', 2], ['str', 'some string']]"); 54 assertRender!(val)("{{ val.length }}", "3"); 55 56 assertRender!(val)("{{ val.idx }}", "2"); 57 58 assertRender!(val)("{{ val.str }}", "some string"); 59 assertRender!(val)("{{ val['str'] }}", "some string"); 60 assertRender!(val)(`{{ val["str"] }}`, "some string"); 61 assertRender!(val)(`{{ val.str.length }}`, "11"); 62 63 assertRender!(val)("{{ val.arr }}", "[1, 2, 3]"); 64 assertRender!(val)("{{ val.arr[0] }}", "1"); 65 assertRender!(val)("{{ val.arr[val.idx - 1] }}", "2"); 66 assertRender!(val)("{{ val.arr.length }}", "3"); 67 } 68 69 // Simple math expressions 70 unittest 71 { 72 assertRender("{{ 1 }}", "1"); 73 assertRender("{{ 1 + 1 }}", "2"); 74 assertRender("{{ 1 - 2 }}", "-1"); 75 assertRender("{{ -2 * 3 }}", "-6"); 76 assertRender("{{ 10 // 3 }}", "3"); 77 assertRender("{{ 10 % 3 }}", "1"); 78 assertRender("{{ 10.0 / 3.0 }}", (10.0/3.0).to!string); 79 } 80 81 82 // Priority 83 unittest 84 { 85 assertRender("{{ 2+2*2**2 }}", "10"); 86 assertRender("{{ ((2+2)*2)**2 }}", "64"); 87 assertRender("{{ 2-2/2 }}", "1"); 88 } 89 90 // Associativity 91 unittest 92 { 93 assertRender("{{ 1-2-3-4 }}", "-8"); 94 assertRender("{{ 2**2**3 }}", "256"); 95 assertRender("{{ 10/5/2 }}", "1"); 96 } 97 98 //Logical expressions 99 unittest 100 { 101 assertRender("{{10 == 9}}", "false"); 102 assertRender("{{10 == 10}}", "true"); 103 assertRender("{{10 == 11}}", "false"); 104 105 assertRender("{{10 != 9}}", "true"); 106 assertRender("{{10 != 10}}", "false"); 107 assertRender("{{10 != 11}}", "true"); 108 109 assertRender("{{10 > 9}}", "true"); 110 assertRender("{{10 > 10}}", "false"); 111 assertRender("{{10 > 11}}", "false"); 112 113 assertRender("{{10 >= 9}}", "true"); 114 assertRender("{{10 >= 10}}", "true"); 115 assertRender("{{10 >= 11}}", "false"); 116 117 assertRender("{{10 < 9}}", "false"); 118 assertRender("{{10 < 10}}", "false"); 119 assertRender("{{10 < 11}}", "true"); 120 121 assertRender("{{10 <= 9}}", "false"); 122 assertRender("{{10 <= 10}}", "true"); 123 assertRender("{{10 <= 11}}", "true"); 124 } 125 126 unittest 127 { 128 assertRender("{{ not true }}", "false"); 129 assertRender("{{ not false }}", "true"); 130 131 assertRender("{{ false or false }}", "false"); 132 assertRender("{{ false or true }}", "true"); 133 assertRender("{{ true or false }}", "true"); 134 assertRender("{{ true or true }}", "true"); 135 136 assertRender("{{ false and false }}", "false"); 137 assertRender("{{ false and true }}", "false"); 138 assertRender("{{ true and false }}", "false"); 139 assertRender("{{ true and true }}", "true"); 140 141 assertRender("{{ true or false and false }}", "true"); 142 assertRender("{{ (true or false) and false }}", "false"); 143 144 // Stop computation prevents error: 145 assertRender("{{ false or false or true or 1 // 0}}", "true"); 146 assertRender("{{ true and true and false and 1 // 0}}", "false"); 147 } 148 149 unittest 150 { 151 assertRender("{{ 1 in [1, 2, 3] }}", "true"); 152 assertRender("{{ 4 in [1, 2, 3] }}", "false"); 153 assertRender("{{ 1 not in [1, 2, 3] }}", "false"); 154 assertRender("{{ 4 not in [1, 2, 3] }}", "true"); 155 156 assertRender("{{ 'key' in {key: 'val'} }}", "true"); 157 assertRender("{{ 'val' in {key: 'val'} }}", "false"); 158 assertRender("{{ 'key' not in {key: 'val'} }}", "false"); 159 assertRender("{{ 'val' not in {key: 'val'} }}", "true"); 160 161 assertRender("{{ 'tri' in 'string' }}", "true"); 162 assertRender("{{ 'tra' in 'string' }}", "false"); 163 assertRender("{{ 'tri' not in 'string' }}", "false"); 164 assertRender("{{ 'tra' not in 'string' }}", "true"); 165 166 assertRender("{{ 1.0 is number}}", "true"); 167 assertRender("{{ 'a' is number}}", "false"); 168 assertRender("{{ 1.0 not is number}}", "false"); 169 assertRender("{{ 'a' not is number}}", "true"); 170 171 assertRender("{{ 'string'|upper }}", "STRING"); 172 assertRender("{{ undefinedVar | d | upper }}", ""); 173 assertRender("{{ undefinedVar | d('undefined') | upper }}", "UNDEFINED"); 174 assertRender("{{ 1 ~ (1>2) ~ 'str' ~ [1] }}", "1falsestr[1]"); 175 assertRender("{{ 1 ~ 1>2 ~ 'str' ~ [1] }}", "false"); 176 177 assertRender("{{ length([1, 2, 3])}}", "3"); 178 } 179 180 unittest 181 { 182 assertRender("{{ 1 if true else 2}}", "1"); 183 assertRender("{{ 1 if false else 2}}", "2"); 184 185 assertRender("{{ '!' ~ (undefVar if undefVar is defined else 'a') ~ '!' }}", "!a!"); 186 } 187 188 unittest 189 { 190 int myStrLen(string str) 191 { 192 return cast(int)str.length; 193 } 194 195 string str = "abcde"; 196 197 assertRender!(myStrLen, str)("{{ myStrLen( '!' ~ str ~ '!') }}", "7"); 198 } 199 200 201 // Implicity cast to string 202 unittest 203 { 204 assertRender("{{ '' ~ 123 }}", "123"); 205 assertRender("{{ '' ~ 1.5 }}", "1.5"); 206 assertRender("{{ '' ~ true }}", "true"); 207 assertRender("{{ '' ~ [1,2,3] }}", "[1, 2, 3]"); 208 assertRender("{{ '' ~ (1,) }}", "[1]"); 209 assertRender("{{ '' ~ {a:1} }}", "{a: 1}"); 210 } 211 212 // Implicity cast to bool 213 unittest 214 { 215 assertRender("{{ false or -1 }}", "true"); 216 assertRender("{{ false or 1 }}", "true"); 217 assertRender("{{ false or 0 }}", "false"); 218 219 assertRender("{{ false or -1.5 }}", "true"); 220 assertRender("{{ false or 1.5 }}", "true"); 221 assertRender("{{ false or 0.0 }}", "false"); 222 223 assertRender("{{ false or 'str' }}", "true"); 224 assertRender("{{ false or ' ' }}", "true"); 225 assertRender("{{ false or '' }}", "false"); 226 227 assertRender("{{ false or [1,2] }}", "true"); 228 assertRender("{{ false or (1,) }}", "true"); 229 assertRender("{{ false or [] }}", "false"); 230 231 assertRender("{{ false or {a:1} }}", "true"); 232 assertRender("{{ false or {} }}", "false"); 233 234 assertRender("{{ false or undefVar }}", "false"); 235 } 236 237 // Implicity cast integer to float 238 unittest 239 { 240 assertRender("{{ 1.5 + 15 }}", (16.5).to!string); 241 } 242 243 244 // WS eating + UTF8 strings/raw data 245 unittest 246 { 247 assertRender( 248 "\u0061\u0101\u0800\U00010000" ~ 249 "{{" ~ 250 "\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u202F\u205F\u00A0\u3000\u0020\t" ~ 251 "\n\r\n\r\u2028\u2029" ~ 252 "'\u0061\u0101\u0800\U00010000'" ~ 253 "\n\r\n\r\u2028\u2029" ~ 254 "\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u202F\u205F\u00A0\u3000\u0020\t" ~ 255 "\n\r\n\r\u2028\u2029" ~ 256 "}}" ~ 257 "\u0061\u0101\u0800\U00010000" 258 , 259 "\u0061\u0101\u0800\U00010000" ~ 260 "\u0061\u0101\u0800\U00010000" ~ 261 "\u0061\u0101\u0800\U00010000" 262 ); 263 }