# SPDX-FileCopyrightText: 2016 Frank Hunleth
# SPDX-FileCopyrightText: 2018 Jon Carstens
#
# SPDX-License-Identifier: Apache-2.0
#
defmodule FramingLineTest do
  use ExUnit.Case
  alias Circuits.UART.Framing.Line

  test "adds framing" do
    {:ok, line} = Line.init(separator: "\n")
    assert {:ok, "\n", ^line} = Line.add_framing("", line)
    assert {:ok, "ABC\n", ^line} = Line.add_framing("ABC", line)
  end

  test "removes framing using newline" do
    {:ok, line} = Line.init(separator: "\n")
    assert {:ok, [""], ^line} = Line.remove_framing("\n", line)
    assert {:ok, ["ABC"], ^line} = Line.remove_framing("ABC\n", line)
    assert {:ok, ["ABC", "DEF"], ^line} = Line.remove_framing("ABC\nDEF\n", line)
  end

  test "clears framing buffer on flush" do
    {:ok, line} = Line.init([])

    assert {:in_frame, [], line} = Line.remove_framing("ABC", line)
    assert line.processed == "ABC"

    line = Line.flush(:receive, line)
    assert Line.buffer_empty?(line) == true
  end

  test "handles partial lines" do
    {:ok, line} = Line.init(separator: "\n")

    assert {:in_frame, [], line} = Line.remove_framing("ABC", line)
    assert {:ok, ["ABC"], line} = Line.remove_framing("\n", line)

    assert {:in_frame, ["DEF"], line} = Line.remove_framing("DEF\nGH", line)
    assert {:ok, ["GH"], line} = Line.remove_framing("\n", line)

    assert Line.buffer_empty?(line) == true
  end

  test "removes framing using crlf" do
    {:ok, line} = Line.init(separator: "\r\n")

    assert {:ok, [""], line} = Line.remove_framing("\r\n", line)
    assert {:ok, ["ABC"], line} = Line.remove_framing("ABC\r\n", line)
    assert {:ok, ["ABC", "DEF"], line} = Line.remove_framing("ABC\r\nDEF\r\n", line)

    assert Line.buffer_empty?(line) == true
  end

  test "handles partial framing using crlf" do
    {:ok, line} = Line.init(separator: "\r\n")

    assert {:in_frame, [], line} = Line.remove_framing("ABC", line)
    assert {:ok, ["ABC"], line} = Line.remove_framing("\r\n", line)

    assert {:in_frame, [], line} = Line.remove_framing("DEF\r", line)
    assert {:ok, ["DEF"], line} = Line.remove_framing("\n", line)

    assert {:in_frame, ["GHI"], line} = Line.remove_framing("GHI\r\nJKL\r", line)
    assert {:ok, ["JKL"], line} = Line.remove_framing("\n", line)

    assert {:in_frame, [], line} = Line.remove_framing("M", line)
    assert {:in_frame, [], line} = Line.remove_framing("N", line)
    assert {:in_frame, [], line} = Line.remove_framing("O", line)
    assert {:in_frame, [], line} = Line.remove_framing("\r", line)
    assert {:ok, ["MNO"], line} = Line.remove_framing("\n", line)

    assert Line.buffer_empty?(line) == true
  end

  test "handles max length" do
    {:ok, line} = Line.init(max_length: 4)

    # One partial result
    assert {:in_frame, [{:partial, "ABCD"}], line} = Line.remove_framing("ABCDEFG", line)
    assert {:ok, ["EFG"], line} = Line.remove_framing("\n", line)

    # Multiple partial results
    assert {:in_frame, [{:partial, "ABCD"}, {:partial, "EFGH"}], line} =
             Line.remove_framing("ABCDEFGHI", line)

    # Add one by one to get a partial result
    assert {:in_frame, [], line} = Line.remove_framing("J", line)
    assert {:in_frame, [], line} = Line.remove_framing("K", line)
    assert {:in_frame, [], line} = Line.remove_framing("L", line)
    assert {:in_frame, [{:partial, "IJKL"}], line} = Line.remove_framing("M", line)
    assert Line.buffer_empty?(line) == false
  end

  test "handles max length at end of line" do
    {:ok, line} = Line.init(max_length: 4)
    assert {:ok, ["ABCD"], ^line} = Line.remove_framing("ABCD\n", line)

    assert {:in_frame, [], line} = Line.remove_framing("EFGH", line)
    assert {:ok, ["EFGH"], line} = Line.remove_framing("\n", line)

    assert Line.buffer_empty?(line) == true
  end
end
