1# coding: utf-8 2from __future__ import absolute_import, division, print_function 3 4import string 5 6from hypothesis.strategies import ( 7 composite, integers, just, lists, one_of, sampled_from, text) 8 9from parver import Version 10 11num_int = integers(min_value=0) 12num_str = num_int.map(str) 13 14 15def epoch(): 16 epoch = num_str.map(lambda s: s + '!') 17 return one_of(just(''), epoch) 18 19 20@composite 21def release(draw): 22 return draw( 23 num_str 24 .map(lambda s: [s] + draw(lists(num_str.map(lambda s: '.' + s)))) 25 .map(lambda l: ''.join(l)) 26 ) 27 28 29def separator(strict=False, optional=False): 30 sep = ['.'] 31 32 if optional: 33 sep.append('') 34 35 if not strict: 36 sep.extend(['-', '_']) 37 38 return sampled_from(sep) 39 40 41@composite 42def pre(draw, strict=False): 43 words = ['a', 'b', 'rc'] 44 if not strict: 45 words.extend(['c', 'alpha', 'beta', 'pre', 'preview']) 46 47 blank = just('') 48 49 sep1 = separator(strict=strict, optional=True) 50 if strict: 51 sep1 = blank 52 53 word = sampled_from(words) 54 55 if strict: 56 sep2 = blank 57 else: 58 sep2 = separator(strict=strict, optional=True) 59 60 num_part = sep2.map(lambda s: s + draw(num_str)) 61 if not strict: 62 num_part = one_of(blank, num_part) 63 64 nonempty = ( 65 sep1 66 .map(lambda s: s + draw(word) + draw(num_part)) 67 ) 68 69 return draw(one_of(blank, nonempty)) 70 71 72@composite 73def post(draw, strict=False): 74 words = ['post'] 75 if not strict: 76 words.extend(['r', 'rev']) 77 78 sep1 = separator(strict=strict, optional=not strict) 79 word = sampled_from(words) 80 81 blank = just('') 82 83 sep2 = separator(strict=strict, optional=True) 84 if strict: 85 sep2 = blank 86 87 num_part = sep2.map(lambda s: s + draw(num_str)) 88 if not strict: 89 num_part = one_of(blank, num_part) 90 91 post = sep1.map(lambda s: s + draw(word) + draw(num_part)) 92 93 if strict: 94 return draw(post) 95 96 post_implicit = num_str.map(lambda s: '-' + s) 97 98 return draw(one_of(blank, post_implicit, post)) 99 100 101@composite 102def dev(draw, strict=False): 103 sep = separator(strict=strict, optional=not strict) 104 105 blank = just('') 106 107 num_part = num_str 108 if not strict: 109 num_part = one_of(blank, num_part) 110 111 return draw(one_of(blank, sep.map(lambda s: s + 'dev' + draw(num_part)))) 112 113 114@composite 115def local_segment(draw): 116 alpha = ( 117 draw(one_of(just(''), integers(0, 9).map(str))) 118 + draw(text(string.ascii_lowercase, min_size=1, max_size=1)) 119 + draw(text(string.ascii_lowercase + string.digits)) 120 ) 121 return draw(one_of(num_str, just(alpha))) 122 123 124@composite 125def local(draw, strict=False): 126 if strict: 127 sep = just('.') 128 else: 129 sep = sampled_from('-_.') 130 131 part = local_segment() 132 sep_part = sep.map(lambda s: s + draw(local_segment())) 133 sep_parts = lists(sep_part).map(lambda l: ''.join(l)) 134 135 return draw(one_of(just(''), part.map(lambda s: '+' + s + draw(sep_parts)))) 136 137 138whitespace = sampled_from(['', '\t', '\n', '\r', '\f', '\v']) 139 140 141def vchar(strict=False): 142 if strict: 143 return just('') 144 return sampled_from(['', 'v']) 145 146 147@composite 148def version_string(draw, strict=False): 149 return ( 150 draw(vchar(strict=strict)) + 151 draw(epoch()) + 152 draw(release()) + 153 draw(pre(strict=strict)) + 154 draw(post(strict=strict)) + 155 draw(dev(strict=strict)) + 156 draw(local(strict=strict)) 157 ) 158 159 160@composite 161def version_strategy(draw, strict=False): 162 return Version.parse(draw(version_string(strict=strict))) 163