diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index b5d6393..7374b9c 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -23,7 +23,7 @@ jobs: otp: '28' steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: setup @@ -32,7 +32,7 @@ jobs: elixir-version: ${{ matrix.pair.elixir }} otp-version: ${{ matrix.pair.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v4 + uses: actions/cache@v5 id: mix-cache with: path: | @@ -62,7 +62,7 @@ jobs: - elixir: '1.19.5' otp: '28' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Setup elixir @@ -71,7 +71,7 @@ jobs: elixir-version: ${{ matrix.pair.elixir }} otp-version: ${{ matrix.pair.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v4 + uses: actions/cache@v5 id: mix-cache with: path: | @@ -96,7 +96,7 @@ jobs: - elixir: '1.19.5' otp: '28' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: erlef/setup-beam@v1 @@ -104,7 +104,7 @@ jobs: elixir-version: ${{ matrix.pair.elixir }} otp-version: ${{ matrix.pair.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v4 + uses: actions/cache@v5 id: mix-cache with: path: | diff --git a/.github/workflows/reuse.yaml b/.github/workflows/reuse.yaml index f55ba90..6e9750f 100644 --- a/.github/workflows/reuse.yaml +++ b/.github/workflows/reuse.yaml @@ -8,6 +8,6 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: REUSE Compliance Check uses: fsfe/reuse-action@v4 diff --git a/test/circular_buffer_test.exs b/test/circular_buffer_test.exs index 82d5563..acf5d29 100644 --- a/test/circular_buffer_test.exs +++ b/test/circular_buffer_test.exs @@ -6,22 +6,30 @@ # defmodule CircularBufferTest do use ExUnit.Case, async: false - use PropCheck + use PropCheck, default_opts: [:quiet, {:numtests, 10_000}] doctest CircularBuffer alias CircularBuffer, as: CB - property "new/1 accepts a max size" do - forall i <- integer() do + property "new/1 returns an empty buffer for positive sizes" do + forall size <- pos_integer() do + cb = CB.new(size) + + cb.max_size == size and + cb.count == 0 and + cb.a == [] and + cb.b == [] and + CB.empty?(cb) + end + end + + property "new/1 raises for non-positive sizes" do + forall n <- non_neg_integer() do try do - buffer = CB.new(i) - buffer.max_size == i + CB.new(-n) + false rescue - FunctionClauseError -> - i <= 0 - - _ -> - false + FunctionClauseError -> true end end end @@ -44,20 +52,26 @@ defmodule CircularBufferTest do end end - property "member?/1" do - items = such_that({a, b} <- {pos_integer(), pos_integer()}, when: a != b) + property "member?/2 reflects buffer contents" do + forall {size, is} <- size_and_list() do + iis = Enum.with_index(is) + buffer = Enum.reduce(iis, CB.new(size), fn i, cb -> CB.insert(cb, i) end) + + kept = Enum.take(iis, -size) + evicted = Enum.drop(iis, -size) - forall {a, b} <- items do - cb = CB.new(1) |> CB.insert(a) - !Enum.member?(cb, b) && Enum.member?(cb, a) + Enum.all?(kept, &Enum.member?(buffer, &1)) and + Enum.all?(evicted, fn x -> not Enum.member?(buffer, x) end) and + not Enum.member?(buffer, :never_inserted) end end property "implements Enumerable" do - forall is <- list(integer()) do - buffer = Enum.reduce(is, CB.new(length(is) + 1), fn i, cb -> CB.insert(cb, i) end) + forall {size, is} <- size_and_list() do + buffer = Enum.reduce(is, CB.new(size), fn i, cb -> CB.insert(cb, i) end) - Enum.reduce(buffer, 0, fn acc, i -> acc + i end) == Enum.sum(is) + Enum.reduce(buffer, 0, fn elem, acc -> acc + elem end) == + Enum.sum(Enum.take(is, -size)) end end @@ -108,11 +122,7 @@ defmodule CircularBufferTest do buffer = Enum.reduce(iis, CB.new(size), fn i, cb -> CB.insert(cb, i) end) - oldest = - iis - |> Enum.reverse() - |> Enum.drop(size - 1) - |> Enum.at(0) + oldest = iis |> Enum.take(-size) |> List.first() CB.oldest(buffer) == oldest end @@ -156,17 +166,11 @@ defmodule CircularBufferTest do def size_and_list do let size <- pos_integer() do - let is <- ints(size * 2 + 1, []) do - {size, is} + let n <- range(0, size * 2 + 1) do + let is <- vector(n, integer()) do + {size, is} + end end end end - - defp ints(0, acc), do: acc - - defp ints(size, acc) do - let i <- integer() do - ints(size - 1, [i | acc]) - end - end end