Skip to content

Commit

Permalink
Added forgotten file
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksei Matiushkin committed Feb 4, 2024
1 parent de8ce3d commit 3271829
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions lib/estructura/stream_data.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
defmodule Estructura.StreamData do
@moduledoc """
Additional generators to be used with `__generator__/1` generated by `Use Estructura`
"""

@typep seed() :: :rand.state()
@typep size() :: non_neg_integer()
@typep generator_fun(a) :: (seed(), size() -> StreamData.LazyTree.t(a))

@typedoc """
An opaque type that represents an `Estructura.StreamData` generator that generates values
of type `a`.
"""
@opaque t(a) :: %StreamData{generator: generator_fun(a)} | Enumerable.t()

@doc "Helper to generate _unshrinkable_ streams as per `Stream.iterate/2`."
@spec iterate(value, (value -> value)) :: StreamData.t(value) when value: term()
def iterate(initial_value, next_fun) when is_function(next_fun, 1) do
initial_value
|> StreamData.constant()
|> StreamData.bind(&StreamData.constant(next_fun.(&1)))
|> StreamData.unshrinkable()
end

@spec date(keyword()) :: StreamData.t(Date.t())
@doc """
Generates an instance of `Date.t()`. This generator is unshrinkable.
"""
def date(options \\ []) do
from = Keyword.get(options, :from, ~D|2000-01-01|)
to = Keyword.get(options, :to, Date.utc_today())
step = Keyword.get(options, :step, :random)

from
|> iterate(fn d ->
next =
case step do
days when is_integer(days) -> Date.add(d, days)
:random -> Date.add(d, Enum.random(-30..30//1))
{:random, num} -> Date.add(d, Enum.random(-num..num//1))
end

case Date.diff(to, next) do
diff when diff <= 0 -> to
diff when diff > 0 -> Date.add(from, diff)
end
end)
end

@spec datetime(keyword()) :: StreamData.t(DateTime.t())
@doc """
Generates an instance of `DateTime.t()`. This generator is unshrinkable.
"""
def datetime(options \\ []) do
from = Keyword.get(options, :from, ~U|2000-01-01T00:00:00Z|)
to = Keyword.get(options, :to, DateTime.utc_now())
step = Keyword.get(options, :step, :random)

from
|> iterate(fn dt ->
next =
case step do
secs when is_integer(secs) -> DateTime.add(dt, secs, :second)
{num, unit} when is_integer(num) -> DateTime.add(dt, num, unit)
:random -> DateTime.add(dt, Enum.random(-86_400..86_400//1), :second)
{:random, num} -> DateTime.add(dt, Enum.random(-num..num//1), :second)
end

case DateTime.diff(to, next) do
diff when diff <= 0 -> to
diff when diff > 0 -> DateTime.add(from, diff)
end
end)
end
end

0 comments on commit 3271829

Please sign in to comment.