module Flores::Random
A collection of methods intended for use in randomized testing.
Constants
- CHARACTERS
A selection of UTF-8 characters
I'd love to generate this, but I don't yet know enough about how unicode blocks are allocated to do that. For now, hardcode a set of possible characters.
- IPV4_MAX
- IPV6_SEGMENT
- LISTEN_BACKLOG
Public Class Methods
Generates a random character (A string of length 1)
@return [String]
# File lib/flores/random.rb, line 69 def self.character return CHARACTERS[integer(0...CHARACTERS.length)] end
Return a random integer value within a given range.
@param range [Range]
# File lib/flores/random.rb, line 76 def self.integer(range) raise ArgumentError, "Range not given, got #{range.class}: #{range.inspect}" if !range.is_a?(Range) rand(range) end
Return a random IPv4 address as a string
# File lib/flores/random.rb, line 110 def self.ipv4 # TODO(sissel): Support CIDR range restriction? # TODO(sissel): Support netmask restriction? [integer(0..IPV4_MAX)].pack("N").unpack("C4").join(".") end
Return a random IPv6 address as a string
The address may be in abbreviated form (ABCD::01EF):w
# File lib/flores/random.rb, line 119 def self.ipv6 # TODO(sissel): Support CIDR range restriction? # TODO(sissel): Support netmask restriction? length = integer(2..8) if length == 8 # Full address; nothing to abbreviate ipv6_pack(length) else abbreviation = ipv6_abbreviation(length) if length == 2 first = 1 second = 1 else first = integer(2...length) second = length - first end ipv6_pack(first) + abbreviation + ipv6_pack(second) end end
Return a random element from an array
# File lib/flores/random.rb, line 105 def self.item(array) array[integer(0...array.size)] end
Run a block a random number of times.
@param range [Fixnum of Range] same meaning as integer(range)
# File lib/flores/random.rb, line 94 def self.iterations(range, &block) range = 0..range if range.is_a?(Numeric) if block_given? integer(range).times(&block) nil else integer(range).times end end
Return a random number within a given range.
@param range [Range]
# File lib/flores/random.rb, line 84 def self.number(range) raise ArgumentError, "Range not given, got #{range.class}: #{range.inspect}" if !range.is_a?(Range) # Ruby 1.9.3 and below do not have Enumerable#size, so we have to compute the size of the range # ourselves. rand * (range.end - range.begin) + range.begin end
Get a TCP socket bound and listening on a random port.
You are responsible for closing the socket.
Returns [socket, address, port]
# File lib/flores/random.rb, line 144 def self.tcp_listener(host = "127.0.0.1") socket_listener(Socket::SOCK_STREAM, host) end
Generates text with random characters of a given length (or within a length range)
-
The length can be a number or a range `x..y`. If a range, it must be ascending (x < y)
-
Negative lengths are not permitted and will raise an ArgumentError
@param length [Fixnum or Range] the length of text to generate @return [String] the generated text
# File lib/flores/random.rb, line 49 def self.text(length) return text_range(length) if length.is_a?(Range) raise ArgumentError, "A negative length is not permitted, I received #{length}" if length < 0 length.times.collect { character }.join end
Generate text with random characters of a length within the given range.
@param range [Range] the range of length to generate, inclusive @return [String] the generated text
# File lib/flores/random.rb, line 60 def self.text_range(range) raise ArgumentError, "Requires ascending range, you gave #{range}." if range.end < range.begin raise ArgumentError, "A negative range values are not permitted, I received range #{range}" if range.begin < 0 text(integer(range)) end
Get a UDP socket bound and listening on a random port.
You are responsible for closing the socket.
Returns [socket, address, port]
# File lib/flores/random.rb, line 153 def self.udp_listener(host = "127.0.0.1") socket_listener(Socket::SOCK_DGRAM, host) end
Private Class Methods
# File lib/flores/random.rb, line 166 def self.ipv6_abbreviation(length) abbreviate = (integer(0..1) == 0) if abbreviate "::" else ":" + (8 - length).times.collect { "0" }.join(":") + ":" end end
# File lib/flores/random.rb, line 162 def self.ipv6_pack(length) length.times.collect { integer(0...IPV6_SEGMENT).to_s(16) }.join(":") end
# File lib/flores/random.rb, line 188 def self.server_socket_class if RUBY_ENGINE == 'jruby' # https://github.com/jruby/jruby/wiki/ServerSocket ServerSocket else Socket end end
# File lib/flores/random.rb, line 176 def self.socket_listener(type, host) socket = server_socket_class.new(Socket::AF_INET, type) socket.bind(Socket.pack_sockaddr_in(0, host)) if type == Socket::SOCK_STREAM || type == Socket::SOCK_SEQPACKET socket.listen(LISTEN_BACKLOG) end port = socket.local_address.ip_port address = socket.local_address.ip_address [socket, address, port] end