# `MoreStreamData`
[🔗](https://github.com/IgnacioGoldchluk/more_stream_data/blob/main/lib/more_stream_data.ex#L1)

Additional generators based on `StreamData`

# `datetime`

```elixir
@spec datetime(Keyword.t()) :: StreamData.t(DateTime.t())
```

Generates `t:DateTime.t/0` structs.

## Options

  - `:min` - (`t:DateTime.t/0`) if present, only datetimes after this value are generated
  - `:max` - (`t:DateTime.t/0`) if present, only datetimes before this value are generated
  - `:date` - (`StreamData.t(Date.t())`) if present, uses this strategy for the date part
  - `:time` - (`StreamData.t(Time.t())`) if present, uses this strategy for the time part

If `:min` and/or `:max` are provided then `:date` and `:time` are ignored

## Shrinking

Shrinks according to the provided options:
- `:min` and/or `:max` provided -> towards `:min`
- `:max` provided -> towards `:max`
- `:date` and/or `:time` provided -> towards the combination of the generators
- No range provided: towards `DateTime.utc_now/0`

# `decimal`

```elixir
@spec decimal(Keyword.t()) :: StreamData.t(Decimal.t())
```

Generates `t:Decimal.t/0` values based on the given `opts`.

## Options

  - `:min` - (`t:Decimal.t/0`) the minimum value to generate (inclusive)
  - `:max` - (`t:Decimal.t/0`) the maximum value to generate (inclusive)
  - `:precision` - (`t:pos_integer/0`) maximum number of decimal places
  - `:allow_nan?` - (`boolean() | nil`) whether to allow `"NaN"`. If `nil`, then
  `"NaN"` is allowed unless both `:min` and `:max` are specified.
  - `:allow_infinity?` - (`boolean() | nil()`) whether to allow `"±Infinity"`. If `nil`,
  `"±Infinity"` is allowed based on `:min` and `:max`. If set to `true`, `"±Infinity"` is
  generated even if `:min` and `:max` are specified.

## Shrinking

Shrinks towards `Decimal.new(0)` or `:min` if specified.

# `domain`

```elixir
@spec domain(Keyword.t()) :: StreamData.t(String.t())
```

Generates valid domains according to [RFC-1035](https://datatracker.ietf.org/doc/html/rfc1035)

Top Level Domains are sampled from the [IANA List](https://data.iana.org/TLD/tlds-alpha-by-domain.txt), excluding
punycode (`"xn--.*"`) domains

## Options

  - `:max_length` - (`t:pos_integer/0`) the maximum length of the entire domain.
  Must be `4 <= :max_length <= 255` as per RFC-1035. Defaults to `255`.
  - `:max_label_length` - (`t:pos_integer/0`) the maximum length of each label.
  Must be `1 <= :max_label_length <= 63` as per RFC-1035. Defaults to `63`.

## Shrinking

Shrinks towards shorter and fewer labels, and to `"com"` top level domain, if allowed by
`:max_length`

# `duration`

```elixir
@spec duration(Keyword.t()) :: StreamData.t(Duration.t())
```

Generates a `t:Duration.t/0` struct.

Shrinks towards all values going to 0. Keep in mind the values in
`Duration.t()` structs can be negative. Therefore calling
`duration(min: Duration.new!(day: 1))` can generate `Duration.new!(day: -20)`

## Options
  - `:min` - (`t:Duration.t/0` `|` `t:Keyword.t/0`) the minimum duration to generate.
  - `:max` - (`t:Duration.t/0` `|` `t:Keyword.t/0`) the maximum duration to generate.

Keep in mind that units are collapsed into months, seconds and microseconds.
Therefore passing `min: [week: 5]` can set any value between `:microsecond` and `:week`,
but `:year` and `:month` are always set to 0. This is because there is no conversion
from `week` to `month`.

## Shrinking
Shrinks towards zero values. Keep in mind the values in `t:Duration.t/0` structs
can be negative. Therefore calling `duration(min: Duration.new!(day: 1))`
can generate `Duration.new!(day: -20)`

# `email`

```elixir
@spec email(Keyword.t()) :: StreamData.t(String.t())
```

Generates valid email addresses.

Does not follow RFC-5322. Instead, it generates emails considered valid by the most
common internet providers. Some differences:
- Addresses are limited to ASCII characters
- No double quotes (`"`) allowed
- No single domain such as `john@doe`
- No IP address as domain

## Options

  - `:domains` - (`StreamData.t(String.t())`) strategy that generates domains. If not
  provided then `domain/1` is used.
  - `:max_length` - (`t:pos_integer/0`) maximum length of the entire email. Must be
  at least `6`, since the shortest possible email is of the form `a@b.cd`. Defaults
  to the maximum email length allowed (254)

## Shrinking
Shrinks towards shorter local parts. The domain part follows `:domains` behaviour.

# `from_regex`

```elixir
@spec from_regex(Regex.t() | String.t(), Keyword.t()) :: StreamData.t(String.t())
```

Generates valid strings from a given regex.

Refer to the [README](./README.md#roadmap) for the list of supported regex features and patterns.

## Options
- `:character_set` - (`:printable | :all`) if set to `:printable` only
printable characters are generated, otherwise every character in the ASCII extended
range 0-255 can be generated. Defaults to `:all`
- `:max_length` - (`t:pos_integer/0`) the maximum string length.

Keep in mind that passing `:max_length` might cause the function to raise. The option
is simply a "hint" to improve the generation of new values. For example,
`MoreStreamData.from_regex(~r/^{10,15}$/, max_length: 8)` raises because the regex cannot
generate strings of the specified `:min_length`. Rely on `:max_length` as last resort only when
the length of the total string cannot be encoded as part of the regex pattern.

## Shrinking
Shrinks towards lower ASCII characters and shorter expressions. For example
`from_regex(~r/[A-Z]+_[a-z]+/)` shrinks towards `A_a`

# `ip_address`

```elixir
@spec ip_address(Keyword.t()) :: StreamData.t(String.t())
```

Generates IPv4 and IPv6 addresses as a string

## Options:

  - `:version` - (`4 | 6`) generates IP adresses only of this version. Defaults to
  generating both IPv4 and IPv6.
  - `:network` - (`t:String.t/0`) A string representing an IPv4 network or an IPv6 network, such
  as `"123.111.0.0/16"` or `"1234:3210::/16`. If specified, only IPs in the given
  range are generated.

  In case both `:version` and `:network` are specified, the version must match the network.

  In case `:network` is not set then IPs from [IPv4 Special Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml)
  and/or [IPv6 Special Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml)
  are generated alongside random IPs for better edge-case coverage.

## Shrinking

  Shrinks towards lower IP addresses. For example
  `ip_address(network: "255.255.255.0/8")` shrinks towards `"255.255.255.0"`

# `more_float`

```elixir
@spec more_float(Keyword.t()) :: StreamData.t(float())
```

Same as `StreamData.float/1` but also accepts exclusion options

## Options

  - `:exclude_min?` - (`t:boolean/0`) whether to exclude the min value if set.
  Defaults to `false`
  - `:exclude_max?` - (`t:boolean/0`) whether to exclude the max value if set.
  Defaults to `false`

## Shrinking

Same as `StreamData.float/1` since the additional options don't modify the underlying
generator

# `more_integer`

Same as `StreamData.integer/0`

# `more_integer`

```elixir
@spec more_integer(Keyword.t() | Range.t()) :: StreamData.t(integer())
```

Same as `StreamData.integer/1` but also accepts a single end instead of
a range.

## Options

  - `:min` - (`t:integer/0`) the minimum inclusive value
  - `:max` - (`t:integer/0`) the maximum inclusive value

## Shrinking

If only one of `:min`, `:max` is specified it shrinks toward the specified limit. In any
other case it behaves as `StreamData.integer/1`

# `sample`

Returns a list of elements from the input enum in random order.

This function can return duplicates if the input enum contains duplicate elements.

## Options

  - `:min_length` - (`t:non_neg_integer/0`) the minimum length of the list. Defaults to 0
  - `:max_length` - (`t:non_neg_integer/0`) the maximum length of the list. Defaults to
  the length of the input enum.

## Shrinking
Shrinks towards smaller lists and in the same order as the original input

# `time`

```elixir
@spec time(Keyword.t()) :: StreamData.t(Time.t())
```

Generates `t:Time.t/0` structs based on the provided `opts`.

## Options

  - `:min` - (`t:Time.t/0`) the minimum time to generate (inclusive)
  - `:max` - (`t:Time.t/0`) the maximum time to generate (inclusive)

## Shrinking

Shrinks towards `~T[00:00:00]` or the specified `:min`.

# `url`

```elixir
@spec url() :: StreamData.t(String.t())
```

Generates valid `http/https` URLs according to [RFC-3986](https://www.rfc-editor.org/rfc/rfc3986.html)

URLs contain ASCII characters only

---

*Consult [api-reference.md](api-reference.md) for complete listing*
