defmodule SnmpKit.SnmpLib.MIBTest do use ExUnit.Case, async: true alias SnmpKit.SnmpLib.MIB alias SnmpKit.SnmpLib.MIB.Error # doctest MIB describe "compile/2" do test "returns error for non-existent file" do result = MIB.compile("nonexistent.mib") assert {:error, errors} = result refute Enum.empty?(errors) assert %Error{type: :file_not_found} = List.first(errors) end test "returns error for invalid file path" do result = MIB.compile("/invalid/path/to/mib.txt") assert {:error, errors} = result refute Enum.empty?(errors) end test "accepts empty options list" do result = MIB.compile("test.mib", []) assert {:error, _errors} = result end test "accepts output_dir option" do result = MIB.compile("test.mib", output_dir: "/tmp/mibs") assert {:error, _errors} = result end test "accepts include_dirs option" do result = MIB.compile("test.mib", include_dirs: ["./priv/mibs", "/usr/share/mibs"]) assert {:error, _errors} = result end test "accepts log_level option" do result = MIB.compile("test.mib", log_level: :debug) assert {:error, _errors} = result end test "accepts format option with :elixir" do result = MIB.compile("test.mib", format: :elixir) assert {:error, _errors} = result end test "accepts format option with :erlang" do result = MIB.compile("test.mib", format: :erlang) assert {:error, _errors} = result end test "accepts format option with :both" do result = MIB.compile("test.mib", format: :both) assert {:error, _errors} = result end test "accepts optimize option" do result = MIB.compile("test.mib", optimize: true) assert {:error, _errors} = result end test "accepts warnings_as_errors option" do result = MIB.compile("test.mib", warnings_as_errors: true) assert {:error, _errors} = result end test "accepts vendor_quirks option" do result = MIB.compile("test.mib", vendor_quirks: false) assert {:error, _errors} = result end test "accepts multiple options together" do result = MIB.compile("test.mib", output_dir: "/tmp", format: :elixir, optimize: true, log_level: :warn ) assert {:error, _errors} = result end test "returns error list with Error structs" do result = MIB.compile("nonexistent.mib") assert {:error, errors} = result assert Enum.all?(errors, &match?(%Error{}, &1)) end test "accepts relative file path" do result = MIB.compile("./test/fixtures/test.mib") assert {:error, _errors} = result end test "accepts absolute file path" do result = MIB.compile("/absolute/path/to/mib.txt") assert {:error, _errors} = result end end describe "compile_string/2" do @tag :yecc_required test "returns error for empty string" do result = MIB.compile_string("") assert {:error, errors} = result refute Enum.empty?(errors) end @tag :yecc_required test "returns error for invalid MIB content" do result = MIB.compile_string("invalid mib content") assert {:error, errors} = result refute Enum.empty?(errors) end @tag :yecc_required test "accepts MIB header format" do mib_content = """ TEST-MIB DEFINITIONS ::= BEGIN END """ result = MIB.compile_string(mib_content) # Should attempt to compile (may fail, but accepts the format) assert is_tuple(result) and elem(result, 0) in [:ok, :error] end @tag :yecc_required test "accepts empty options list" do result = MIB.compile_string("TEST-MIB DEFINITIONS ::= BEGIN END", []) assert is_tuple(result) and elem(result, 0) in [:ok, :error] end @tag :yecc_required test "accepts output_dir option" do result = MIB.compile_string("content", output_dir: "/tmp") assert {:error, _errors} = result end @tag :yecc_required test "accepts format option" do result = MIB.compile_string("content", format: :elixir) assert {:error, _errors} = result end @tag :yecc_required test "accepts include_dirs option" do result = MIB.compile_string("content", include_dirs: ["./priv/mibs"]) assert {:error, _errors} = result end @tag :yecc_required test "accepts multiple options" do result = MIB.compile_string("content", output_dir: "/tmp", format: :erlang, optimize: false ) assert {:error, _errors} = result end @tag :yecc_required test "handles binary string input" do result = MIB.compile_string(<<65, 66, 67>>) assert {:error, _errors} = result end @tag :yecc_required test "handles long MIB content" do long_content = String.duplicate("TEST-MIB DEFINITIONS ::= BEGIN\n", 100) <> "END" result = MIB.compile_string(long_content) assert is_tuple(result) and elem(result, 0) in [:ok, :error] end @tag :yecc_required test "returns error list for invalid content" do result = MIB.compile_string("invalid") assert {:error, errors} = result assert Enum.all?(errors, &match?(%Error{}, &1)) end end describe "load_compiled/1" do test "returns error for non-existent compiled file" do result = MIB.load_compiled("nonexistent_compiled.ex") assert {:error, _reason} = result end test "returns error for invalid file path" do result = MIB.load_compiled("/invalid/path/compiled.ex") assert {:error, _reason} = result end test "accepts .ex file extension" do result = MIB.load_compiled("lib/generated/test_mib.ex") assert {:error, _reason} = result end test "accepts .beam file extension" do result = MIB.load_compiled("lib/generated/test_mib.beam") assert {:error, _reason} = result end test "accepts relative path" do result = MIB.load_compiled("./compiled/mib.ex") assert {:error, _reason} = result end test "accepts absolute path" do result = MIB.load_compiled("/absolute/path/to/compiled.ex") assert {:error, _reason} = result end test "error includes reason" do result = MIB.load_compiled("nonexistent.ex") assert {:error, reason} = result valid? = is_atom(reason) or is_binary(reason) or is_tuple(reason) assert valid? end end describe "compile_all/2" do test "returns error for empty list" do result = MIB.compile_all([]) # Empty list might return {:ok, []} or {:error, ...} depending on implementation assert is_tuple(result) and elem(result, 0) in [:ok, :error] end test "returns error for list with non-existent files" do result = MIB.compile_all(["nonexistent1.mib", "nonexistent2.mib"]) assert {:error, errors} = result refute Enum.empty?(errors) end test "accepts single file in list" do result = MIB.compile_all(["test.mib"]) assert {:error, _errors} = result end test "accepts multiple files in list" do result = MIB.compile_all(["file1.mib", "file2.mib", "file3.mib"]) assert {:error, _errors} = result end test "accepts empty options list" do result = MIB.compile_all(["test.mib"], []) assert {:error, _errors} = result end test "accepts output_dir option" do result = MIB.compile_all(["test.mib"], output_dir: "/tmp") assert {:error, _errors} = result end test "accepts format option" do result = MIB.compile_all(["test.mib"], format: :elixir) assert {:error, _errors} = result end test "accepts include_dirs option" do result = MIB.compile_all(["test.mib"], include_dirs: ["./mibs"]) assert {:error, _errors} = result end test "accepts multiple options" do result = MIB.compile_all(["test.mib"], output_dir: "/tmp", format: :both, optimize: true ) assert {:error, _errors} = result end test "handles mix of valid and invalid file paths" do result = MIB.compile_all(["valid.mib", "/invalid/path.mib", "another.mib"]) assert {:error, _errors} = result end test "error includes file associations" do result = MIB.compile_all(["file1.mib", "file2.mib"]) assert {:error, errors} = result # Errors should be associated with files refute Enum.empty?(errors) end test "accepts list with dependency order" do # Simulating dependency order: base MIBs first, dependent MIBs later result = MIB.compile_all(["SNMPv2-SMI.txt", "SNMPv2-TC.txt", "RFC1213-MIB.txt"]) assert {:error, _errors} = result end end describe "option validation" do test "compile handles invalid option keys gracefully" do result = MIB.compile("test.mib", invalid_key: "value") # Should still attempt to compile, ignoring invalid keys assert {:error, _errors} = result end @tag :yecc_required test "compile_string handles invalid option keys gracefully" do result = MIB.compile_string("content", invalid_key: "value") assert {:error, _errors} = result end test "compile_all handles invalid option keys gracefully" do result = MIB.compile_all(["test.mib"], invalid_key: "value") assert {:error, _errors} = result end end describe "return value structure" do test "compile returns tuple with :error or :ok" do result = MIB.compile("test.mib") assert tuple_size(result) == 2 assert elem(result, 0) in [:ok, :error, :warning] end @tag :yecc_required test "compile_string returns tuple with :error or :ok" do result = MIB.compile_string("content") assert tuple_size(result) == 2 assert elem(result, 0) in [:ok, :error, :warning] end test "load_compiled returns tuple with :error or :ok" do result = MIB.load_compiled("compiled.ex") assert tuple_size(result) == 2 assert elem(result, 0) in [:ok, :error] end test "compile_all returns tuple with :error or :ok" do result = MIB.compile_all(["test.mib"]) assert tuple_size(result) == 2 assert elem(result, 0) in [:ok, :error] end end describe "error handling" do test "compile handles various file path errors gracefully" do # These should all return errors without crashing assert {:error, _} = MIB.compile("") assert {:error, _} = MIB.compile("/nonexistent/path") assert {:error, _} = MIB.compile("../../../etc/passwd") end @tag :yecc_required test "compile_string handles invalid content gracefully" do assert {:error, _} = MIB.compile_string("") assert {:error, _} = MIB.compile_string("not valid MIB content") assert {:error, _} = MIB.compile_string("123 456 789") end test "load_compiled handles invalid paths gracefully" do assert {:error, _} = MIB.load_compiled("") assert {:error, _} = MIB.load_compiled("/nonexistent/file.ex") assert {:error, _} = MIB.load_compiled("../invalid/path.ex") end test "compile_all handles empty and invalid lists gracefully" do # Empty list case result = MIB.compile_all([]) assert is_tuple(result) and elem(result, 0) in [:ok, :error] # List with invalid paths assert {:error, _} = MIB.compile_all(["", "/nonexistent"]) end end describe "default options" do test "compile uses defaults when options not provided" do result1 = MIB.compile("test.mib") result2 = MIB.compile("test.mib", []) # Both should behave similarly with defaults assert match?({:error, _}, result1) assert match?({:error, _}, result2) end @tag :yecc_required test "compile_string uses defaults when options not provided" do result1 = MIB.compile_string("content") result2 = MIB.compile_string("content", []) assert match?({:error, _}, result1) assert match?({:error, _}, result2) end test "compile_all uses defaults when options not provided" do result1 = MIB.compile_all(["test.mib"]) result2 = MIB.compile_all(["test.mib"], []) assert match?({:error, _}, result1) assert match?({:error, _}, result2) end end end