1import datetime 2 3from babel.dates import get_timezone 4from markupsafe import escape 5from markupsafe import Markup 6 7from lektor._compat import itervalues 8from lektor._compat import text_type 9from lektor.context import Context 10from lektor.datamodel import Field 11from lektor.types import BadValue 12from lektor.types import Undefined 13from lektor.types.formats import MarkdownDescriptor 14 15 16class DummySource(object): 17 url_path = "/" 18 19 20def make_field(env, type, **options): 21 return Field(env, "demo", type=env.types[type], options=options) 22 23 24def test_markdown(env, pad): 25 field = make_field(env, "markdown") 26 27 source = DummySource() 28 29 with Context(pad=pad): 30 rv = field.deserialize_value("Hello **World**!", pad=pad) 31 assert isinstance(rv, MarkdownDescriptor) 32 rv = rv.__get__(source) 33 assert rv 34 assert rv.source == "Hello **World**!" 35 assert escape(rv) == Markup("<p>Hello <strong>World</strong>!</p>\n") 36 assert rv.meta == {} 37 38 for val in "", None: 39 rv = field.deserialize_value(val, pad=pad) 40 assert isinstance(rv, MarkdownDescriptor) 41 rv = rv.__get__(source) 42 assert not rv 43 assert rv.source == "" 44 assert escape(rv) == Markup("") 45 assert rv.meta == {} 46 47 48def test_markdown_links(env, pad): 49 field = make_field(env, "markdown") 50 source = DummySource() 51 52 def md(s): 53 rv = field.deserialize_value(s, pad=pad) 54 assert isinstance(rv, MarkdownDescriptor) 55 return text_type(rv.__get__(source)).strip() 56 57 with Context(pad=pad): 58 assert md("[foo](http://example.com/)") == ( 59 '<p><a href="http://example.com/">foo</a></p>' 60 ) 61 assert md("[foo](javascript:foo)") == ( 62 '<p><a href="javascript:foo">foo</a></p>' 63 ) 64 65 img = ( 66 "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4" 67 "//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" 68 ) 69 assert ( 70 md("![test](data:image/png;base64,%s)" % img) 71 == ('<p><img src="data:image/png;base64,%s" alt="test"></p>') % img 72 ) 73 74 75def test_markdown_linking(pad, builder): 76 blog_index = pad.get("/blog", page_num=1) 77 78 prog, _ = builder.build(blog_index) 79 with prog.artifacts[0].open("rb") as f: 80 assert ( 81 b'Look at my <a href="2015/12/post1/hello.txt">' b"attachment</a>" 82 ) in f.read() 83 84 blog_post = pad.get("/blog/post1") 85 86 prog, _ = builder.build(blog_post) 87 with prog.artifacts[0].open("rb") as f: 88 assert b'Look at my <a href="hello.txt">' b"attachment</a>" in f.read() 89 90 91def test_markdown_images(pad, builder): 92 blog_index = pad.get("/blog", page_num=1) 93 94 prog, _ = builder.build(blog_index) 95 with prog.artifacts[0].open("rb") as f: 96 assert ( 97 b'This is an image <img src="2015/12/' b'post1/logo.png" alt="logo">.' 98 ) in f.read() 99 100 blog_post = pad.get("/blog/post1") 101 102 prog, _ = builder.build(blog_post) 103 with prog.artifacts[0].open("rb") as f: 104 assert b'This is an image <img src="logo.png" alt="logo">.' in f.read() 105 106 107def test_string(env, pad): 108 field = make_field(env, "string") 109 110 with Context(pad=pad): 111 rv = field.deserialize_value("", pad=pad) 112 assert rv == "" 113 114 rv = field.deserialize_value(None, pad=pad) 115 assert isinstance(rv, Undefined) 116 117 rv = field.deserialize_value("foo\nbar", pad=pad) 118 assert rv == "foo" 119 120 rv = field.deserialize_value(" 123 ", pad=pad) 121 assert rv == "123" 122 123 124def test_text(env, pad): 125 field = make_field(env, "text") 126 127 with Context(pad=pad): 128 rv = field.deserialize_value("", pad=pad) 129 assert rv == "" 130 131 rv = field.deserialize_value(None, pad=pad) 132 assert isinstance(rv, Undefined) 133 134 rv = field.deserialize_value("foo\nbar", pad=pad) 135 assert rv == "foo\nbar" 136 137 rv = field.deserialize_value(" 123 ", pad=pad) 138 assert rv == " 123 " 139 140 141def test_integer(env, pad): 142 field = make_field(env, "integer") 143 144 with Context(pad=pad): 145 rv = field.deserialize_value("", pad=pad) 146 assert isinstance(rv, BadValue) 147 148 rv = field.deserialize_value(None, pad=pad) 149 assert isinstance(rv, Undefined) 150 151 rv = field.deserialize_value("42", pad=pad) 152 assert rv == 42 153 154 rv = field.deserialize_value(" 23 ", pad=pad) 155 assert rv == 23 156 157 158def test_float(env, pad): 159 field = make_field(env, "float") 160 161 with Context(pad=pad): 162 rv = field.deserialize_value("", pad=pad) 163 assert isinstance(rv, BadValue) 164 165 rv = field.deserialize_value(None, pad=pad) 166 assert isinstance(rv, Undefined) 167 168 rv = field.deserialize_value("42", pad=pad) 169 assert rv == 42.0 170 171 rv = field.deserialize_value(" 23.0 ", pad=pad) 172 assert rv == 23.0 173 174 rv = field.deserialize_value("-23.5", pad=pad) 175 assert rv == -23.5 176 177 178def test_boolean(env, pad): 179 field = make_field(env, "boolean") 180 181 with Context(pad=pad): 182 rv = field.deserialize_value("", pad=pad) 183 assert isinstance(rv, BadValue) 184 185 rv = field.deserialize_value(None, pad=pad) 186 assert isinstance(rv, Undefined) 187 188 for s in "true", "TRUE", "True", "1", "yes": 189 rv = field.deserialize_value(s, pad=pad) 190 assert rv is True 191 192 for s in "false", "FALSE", "False", "0", "no": 193 rv = field.deserialize_value(s, pad=pad) 194 assert rv is False 195 196 197def test_datetime(env, pad): 198 field = make_field(env, "datetime") 199 200 with Context(pad=pad): 201 # default 202 rv = field.deserialize_value("2016-04-30 01:02:03", pad=pad) 203 assert isinstance(rv, datetime.datetime) 204 assert rv.year == 2016 205 assert rv.month == 4 206 assert rv.day == 30 207 assert rv.hour == 1 208 assert rv.minute == 2 209 assert rv.second == 3 210 assert rv.tzinfo is None 211 212 # It is not datetime, it is None 213 rv = field.deserialize_value(None, pad=pad) 214 assert isinstance(rv, Undefined) 215 216 # It is not datetime, it is empty string 217 rv = field.deserialize_value("", pad=pad) 218 assert isinstance(rv, BadValue) 219 220 # It is not datetime, it is date 221 rv = field.deserialize_value("2016-04-30", pad=pad) 222 assert isinstance(rv, BadValue) 223 224 225def test_datetime_timezone_utc(env, pad): 226 field = make_field(env, "datetime") 227 with Context(pad=pad): 228 # Known timezone name, UTC 229 rv = field.deserialize_value("2016-04-30 01:02:03 UTC", pad=pad) 230 assert isinstance(rv, datetime.datetime) 231 assert rv.year == 2016 232 assert rv.month == 4 233 assert rv.day == 30 234 assert rv.hour == 1 235 assert rv.minute == 2 236 assert rv.second == 3 237 assert rv.tzinfo is get_timezone("UTC") 238 239 240def test_datetime_timezone_est(env, pad): 241 field = make_field(env, "datetime") 242 with Context(pad=pad): 243 # Known timezone name, EST 244 rv = field.deserialize_value("2016-04-30 01:02:03 EST", pad=pad) 245 assert isinstance(rv, datetime.datetime) 246 assert rv.year == 2016 247 assert rv.month == 4 248 assert rv.day == 30 249 assert rv.hour == 1 250 assert rv.minute == 2 251 assert rv.second == 3 252 assert rv.tzinfo is get_timezone("EST") 253 254 255def test_datetime_timezone_location(env, pad): 256 field = make_field(env, "datetime") 257 with Context(pad=pad): 258 # Known location name, Asia/Seoul 259 rv = field.deserialize_value("2016-04-30 01:02:03 Asia/Seoul", pad=pad) 260 assert isinstance(rv, datetime.datetime) 261 assert rv.year == 2016 262 assert rv.month == 4 263 assert rv.day == 30 264 assert rv.hour == 1 265 assert rv.minute == 2 266 assert rv.second == 3 267 tzinfos = get_timezone("Asia/Seoul")._tzinfos # pylint: disable=no-member 268 assert rv.tzinfo in itervalues(tzinfos) 269 270 271def test_datetime_timezone_kst(env, pad): 272 field = make_field(env, "datetime") 273 with Context(pad=pad): 274 # KST - http://www.timeanddate.com/time/zones/kst 275 rv = field.deserialize_value("2016-04-30 01:02:03 +0900", pad=pad) 276 assert isinstance(rv, datetime.datetime) 277 assert rv.year == 2016 278 assert rv.month == 4 279 assert rv.day == 30 280 assert rv.hour == 1 281 assert rv.minute == 2 282 assert rv.second == 3 283 assert rv.tzinfo._offset == datetime.timedelta(0, 9 * 60 * 60) 284 285 286def test_datetime_timezone_acst(env, pad): 287 field = make_field(env, "datetime") 288 with Context(pad=pad): 289 # ACST - http://www.timeanddate.com/time/zones/acst 290 rv = field.deserialize_value("2016-04-30 01:02:03 +0930", pad=pad) 291 assert isinstance(rv, datetime.datetime) 292 assert rv.year == 2016 293 assert rv.month == 4 294 assert rv.day == 30 295 assert rv.hour == 1 296 assert rv.minute == 2 297 assert rv.second == 3 298 assert rv.tzinfo._offset == datetime.timedelta(0, (9 * 60 + 30) * 60) 299 300 301def test_datetime_timezone_mst(env, pad): 302 field = make_field(env, "datetime") 303 with Context(pad=pad): 304 # MST - http://www.timeanddate.com/time/zones/mst 305 rv = field.deserialize_value("2016-04-30 01:02:03 -0700", pad=pad) 306 assert isinstance(rv, datetime.datetime) 307 assert rv.year == 2016 308 assert rv.month == 4 309 assert rv.day == 30 310 assert rv.hour == 1 311 assert rv.minute == 2 312 assert rv.second == 3 313 assert rv.tzinfo._offset == datetime.timedelta(0, -7 * 60 * 60) 314 315 316def test_datetime_timezone_mart(env, pad): 317 field = make_field(env, "datetime") 318 with Context(pad=pad): 319 # MART - http://www.timeanddate.com/time/zones/mart 320 rv = field.deserialize_value("2016-04-30 01:02:03 -0930", pad=pad) 321 assert isinstance(rv, datetime.datetime) 322 assert rv.year == 2016 323 assert rv.month == 4 324 assert rv.day == 30 325 assert rv.hour == 1 326 assert rv.minute == 2 327 assert rv.second == 3 328 assert rv.tzinfo._offset == datetime.timedelta(0, -(9 * 60 + 30) * 60) 329 330 331def test_datetime_timezone_name(env, pad): 332 field = make_field(env, "datetime") 333 with Context(pad=pad): 334 # with timezone name (case 1) 335 rv = field.deserialize_value("2016-04-30 01:02:03 KST +0900", pad=pad) 336 assert isinstance(rv, datetime.datetime) 337 assert rv.year == 2016 338 assert rv.month == 4 339 assert rv.day == 30 340 assert rv.hour == 1 341 assert rv.minute == 2 342 assert rv.second == 3 343 assert rv.tzinfo._offset == datetime.timedelta(0, 9 * 60 * 60) 344 345 # with timezone name (case 2) 346 rv = field.deserialize_value("2016-04-30 01:02:03 KST+0900", pad=pad) 347 assert isinstance(rv, datetime.datetime) 348 assert rv.year == 2016 349 assert rv.month == 4 350 assert rv.day == 30 351 assert rv.hour == 1 352 assert rv.minute == 2 353 assert rv.second == 3 354 assert rv.tzinfo._offset == datetime.timedelta(0, 9 * 60 * 60) 355