Skip to content

Commit 4e536ca

Browse files
Merge pull request #1 from pappersverk/initial-tests
Add tests
2 parents e69e902 + afeee6f commit 4e536ca

11 files changed

Lines changed: 336 additions & 3 deletions

File tree

.github/workflows/tests.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ '*' ]
8+
9+
jobs:
10+
build:
11+
12+
name: Build and test
13+
runs-on: ubuntu-latest
14+
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
elixir: [ '1.11', '1.12', '1.13' ]
19+
otp: [ '22', '23', '24', '25' ]
20+
exclude:
21+
- elixir: '1.11'
22+
otp: '25'
23+
- elixir: '1.12'
24+
otp: '25'
25+
26+
steps:
27+
- uses: actions/checkout@v2
28+
- name: Set up Elixir
29+
uses: erlef/setup-beam@v1
30+
with:
31+
elixir-version: ${{ matrix.elixir }}
32+
otp-version: ${{ matrix.otp }}
33+
- name: Restore dependencies cache
34+
uses: actions/cache@v2
35+
with:
36+
path: deps
37+
key: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-${{ hashFiles('**/mix.lock') }}
38+
restore-keys: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-
39+
- name: Install dependencies
40+
run: mix deps.get
41+
- name: Run tests
42+
run: mix test

lib/oled_virtual/config.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule OLEDVirtual.Config do
99
end
1010

1111
def validate(config) when is_map(config) do
12-
keys = [:width, :height, :on_display]
12+
keys = [:width, :height, :on_display, :on_buffer_update]
1313

1414
Enum.reduce(keys, :ok, fn key, acc ->
1515
case acc do

lib/oled_virtual/display/server.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ defmodule OLEDVirtual.Display.Server do
117117
def handle_call({:put_buffer, data}, _from, state) do
118118
state = %{state | buffer: data}
119119

120-
{:reply, :ok, state}
120+
{:reply, :ok, state, {:continue, :notifiy_buffer_update}}
121121
end
122122

123123
def handle_call(:get_buffer, _from, %{buffer: buffer} = state) do

mix.exs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ defmodule OLEDVirtual.MixProject do
77
[
88
app: :oled_virtual,
99
version: @version,
10-
elixir: "~> 1.7",
10+
elixir: "~> 1.11",
11+
elixirc_paths: elixirc_paths(Mix.env()),
1112
start_permanent: Mix.env() == :prod,
1213
deps: deps(),
1314
docs: docs(),
@@ -22,6 +23,9 @@ defmodule OLEDVirtual.MixProject do
2223
]
2324
end
2425

26+
defp elixirc_paths(:test), do: ["lib", "test/support"]
27+
defp elixirc_paths(_), do: ["lib"]
28+
2529
# Run "mix help deps" to learn about dependencies.
2630
defp deps do
2731
[

test/oled_virtual/config_test.exs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
defmodule OLEDVirtual.ConfigTest do
2+
use ExUnit.Case, async: true
3+
4+
alias OLEDVirtual.Config
5+
6+
defmodule DummyCallbackModule do
7+
def on_display(_frame, _dimensions), do: :ok
8+
def invalid_on_display(_frame), do: :ok
9+
10+
def on_buffer_update(_frame, _dimensions), do: :ok
11+
def invalid_on_buffer_update(_frame), do: :ok
12+
end
13+
14+
describe "validate/1" do
15+
test "config must be a keyword list or map" do
16+
assert {:error, _} = Config.validate(nil)
17+
assert {:error, _} = Config.validate(1)
18+
assert {:error, _} = Config.validate(1.5)
19+
assert {:error, _} = Config.validate(true)
20+
assert {:error, _} = Config.validate("foo")
21+
assert {:error, _} = Config.validate({:foo})
22+
assert :ok = Config.validate(%{width: 16, height: 8})
23+
assert :ok = Config.validate(width: 16, height: 8)
24+
end
25+
end
26+
27+
describe "validate/2 for :width" do
28+
test "value must be a number" do
29+
assert :ok = Config.validate(%{width: 8}, :width)
30+
assert {:error, _} = Config.validate(%{width: nil}, :width)
31+
assert {:error, _} = Config.validate(%{width: :foo}, :width)
32+
assert {:error, _} = Config.validate(%{width: "foo"}, :width)
33+
assert {:error, _} = Config.validate(%{width: true}, :width)
34+
end
35+
36+
test "value must be a multiple of 8" do
37+
assert :ok = Config.validate(%{width: 8}, :width)
38+
assert {:error, _} = Config.validate(%{width: 5}, :width)
39+
end
40+
41+
test "value is required" do
42+
assert :ok = Config.validate(%{width: 8}, :width)
43+
assert {:error, _} = Config.validate(%{}, :width)
44+
end
45+
end
46+
47+
describe "validate/2 for :height" do
48+
test "value must be a number" do
49+
assert :ok = Config.validate(%{height: 8}, :height)
50+
assert {:error, _} = Config.validate(%{height: nil}, :height)
51+
assert {:error, _} = Config.validate(%{height: :foo}, :height)
52+
assert {:error, _} = Config.validate(%{height: "foo"}, :height)
53+
assert {:error, _} = Config.validate(%{height: true}, :height)
54+
end
55+
56+
test "value must be a multiple of 8" do
57+
assert :ok = Config.validate(%{height: 8}, :height)
58+
assert {:error, _} = Config.validate(%{height: 5}, :height)
59+
end
60+
61+
test "value is required" do
62+
assert :ok = Config.validate(%{height: 8}, :height)
63+
assert {:error, _} = Config.validate(%{}, :height)
64+
end
65+
end
66+
67+
describe "validate/2 for :on_display" do
68+
test "value must be [mod, func]" do
69+
assert :ok = Config.validate(%{on_display: [DummyCallbackModule, :on_display]}, :on_display)
70+
assert {:error, _} = Config.validate(%{on_display: nil}, :on_display)
71+
assert {:error, _} = Config.validate(%{on_display: 1}, :on_display)
72+
assert {:error, _} = Config.validate(%{on_display: :foo}, :on_display)
73+
assert {:error, _} = Config.validate(%{on_display: "foo"}, :on_display)
74+
assert {:error, _} = Config.validate(%{on_display: true}, :on_display)
75+
end
76+
77+
test "[mod, func] must exist with an arity of 2" do
78+
assert :ok = Config.validate(%{on_display: [DummyCallbackModule, :on_display]}, :on_display)
79+
80+
assert {:error, _} =
81+
Config.validate(
82+
%{on_display: [DummyCallbackModule, :invalid_on_display]},
83+
:on_display
84+
)
85+
end
86+
87+
test "value can be optional" do
88+
assert :ok = Config.validate(%{}, :on_display)
89+
end
90+
end
91+
92+
describe "validate/2 for :on_buffer_update" do
93+
test "value must be [mod, func]" do
94+
assert :ok =
95+
Config.validate(
96+
%{on_buffer_update: [DummyCallbackModule, :on_buffer_update]},
97+
:on_buffer_update
98+
)
99+
100+
assert {:error, _} = Config.validate(%{on_buffer_update: nil}, :on_buffer_update)
101+
assert {:error, _} = Config.validate(%{on_buffer_update: 1}, :on_buffer_update)
102+
assert {:error, _} = Config.validate(%{on_buffer_update: :foo}, :on_buffer_update)
103+
assert {:error, _} = Config.validate(%{on_buffer_update: "foo"}, :on_buffer_update)
104+
assert {:error, _} = Config.validate(%{on_buffer_update: true}, :on_buffer_update)
105+
end
106+
107+
test "[mod, func] must exist with an arity of 2" do
108+
assert :ok =
109+
Config.validate(
110+
%{on_buffer_update: [DummyCallbackModule, :on_buffer_update]},
111+
:on_buffer_update
112+
)
113+
114+
assert {:error, _} =
115+
Config.validate(
116+
%{on_buffer_update: [DummyCallbackModule, :invalid_on_buffer_update]},
117+
:on_buffer_update
118+
)
119+
end
120+
121+
test "value can be optional" do
122+
assert :ok = Config.validate(%{}, :on_buffer_update)
123+
end
124+
end
125+
end
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
defmodule OLEDVirtual.Display.ServerTest do
2+
use ExUnit.Case
3+
require Logger
4+
import ExUnit.CaptureLog
5+
6+
alias OLEDVirtual.Display.Server
7+
8+
setup do
9+
{:ok, pid} =
10+
Server.start_link(%{
11+
width: 16,
12+
height: 8,
13+
on_display: [__MODULE__, :on_display_callback],
14+
on_buffer_update: [__MODULE__, :on_buffer_update_callback]
15+
})
16+
17+
%{server: pid}
18+
end
19+
20+
test "get_frame/1 returns the current frame", context do
21+
capture_log(fn ->
22+
Server.display(context.server)
23+
end)
24+
25+
assert {:ok, <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>} =
26+
Server.get_frame(context.server)
27+
end
28+
29+
test "put_buffer/2 and get_buffer/1 retrieve and change the buffer", context do
30+
assert {:ok, <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>} =
31+
Server.get_buffer(context.server)
32+
33+
capture_log(fn ->
34+
Server.put_buffer(context.server, <<255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>)
35+
end)
36+
37+
assert {:ok, <<255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>} =
38+
Server.get_buffer(context.server)
39+
end
40+
41+
test "on_display callback gets called", context do
42+
assert capture_log(fn ->
43+
Server.display(context.server)
44+
# give the logger a bit of time to actually log the message
45+
Process.sleep(50)
46+
end) =~ "on_display_callback/2 called"
47+
end
48+
49+
test "on_buffer_update callback gets called", context do
50+
assert capture_log(fn ->
51+
Server.put_pixel(context.server, 5, 5)
52+
Process.sleep(50)
53+
end) =~ "on_buffer_update_callback/2 called"
54+
end
55+
56+
def on_display_callback(_data, _dimensions) do
57+
Logger.info("on_display_callback/2 called")
58+
end
59+
60+
def on_buffer_update_callback(_data, _dimensions) do
61+
Logger.info("on_buffer_update_callback/2 called")
62+
end
63+
end

test/oled_virtual/format_test.exs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
defmodule OLEDVirtual.FormatTest do
2+
use ExUnit.Case, async: true
3+
4+
alias OLEDVirtual.Format
5+
6+
test "as_matrix/2" do
7+
result = Format.as_matrix(<<255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255>>, 16)
8+
9+
assert [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = Enum.at(result, 0)
10+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 1)
11+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 2)
12+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 3)
13+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 4)
14+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 5)
15+
assert [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] = Enum.at(result, 6)
16+
assert [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = Enum.at(result, 7)
17+
end
18+
19+
test "as_bits/1" do
20+
result = Format.as_bits(<<255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255>>)
21+
22+
assert [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = Enum.take(result, 16)
23+
assert [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = Enum.take(result, -16)
24+
end
25+
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
defmodule OLEDVirtual.MultiDisplayTest do
2+
use ExUnit.Case
3+
import ExUnit.CaptureLog
4+
5+
setup_all do
6+
Application.put_env(:olev_virtual_test, OLEDVirtual.TestMultiDisplay,
7+
displays: [
8+
OLEDVirtual.TestDisplayOne,
9+
OLEDVirtual.TestDisplayTwo
10+
]
11+
)
12+
end
13+
14+
test "invokes a function on all configured displays" do
15+
fun = fn ->
16+
assert [{OLEDVirtual.TestDisplayOne, :ok}, {OLEDVirtual.TestDisplayTwo, :ok}] =
17+
OLEDVirtual.TestMultiDisplay.display()
18+
end
19+
20+
assert capture_log(fun) =~ "display/0 on TestDisplayOne"
21+
assert capture_log(fun) =~ "display/0 on TestDisplayTwo"
22+
end
23+
24+
test "sends a telemetry event per display function invocation", context do
25+
self = self()
26+
27+
# telemetry handler is inside capture_log to prevent log message about anonymous function
28+
capture_log(fn ->
29+
:telemetry.attach(
30+
"#{context.test}",
31+
[:oled_virtual, :multi_display, :display],
32+
fn name, measurements, metadata, _ ->
33+
send(self, {:telemetry_event, name, measurements, metadata})
34+
end,
35+
nil
36+
)
37+
end)
38+
39+
capture_log(fn ->
40+
OLEDVirtual.TestMultiDisplay.display()
41+
end)
42+
43+
assert_receive {:telemetry_event, [:oled_virtual, :multi_display, :display], %{duration: _},
44+
%{
45+
display: OLEDVirtual.TestDisplayOne,
46+
multi_display: OLEDVirtual.TestMultiDisplay
47+
}}
48+
49+
assert_receive {:telemetry_event, [:oled_virtual, :multi_display, :display], %{duration: _},
50+
%{
51+
display: OLEDVirtual.TestDisplayTwo,
52+
multi_display: OLEDVirtual.TestMultiDisplay
53+
}}
54+
end
55+
end

test/support/test_display_one.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
defmodule OLEDVirtual.TestDisplayOne do
2+
require Logger
3+
4+
def display() do
5+
Logger.info("display/0 on TestDisplayOne")
6+
:ok
7+
end
8+
end

test/support/test_display_two.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
defmodule OLEDVirtual.TestDisplayTwo do
2+
require Logger
3+
4+
def display() do
5+
Logger.info("display/0 on TestDisplayTwo")
6+
:ok
7+
end
8+
end

0 commit comments

Comments
 (0)