diff --git a/.credo.exs b/.credo.exs index b8ac9826..1e188300 100644 --- a/.credo.exs +++ b/.credo.exs @@ -173,15 +173,15 @@ {Jump.CredoChecks.AvoidFunctionLevelElse}, {Jump.CredoChecks.AvoidLoggerConfigureInTest}, {Jump.CredoChecks.AvoidSocketAssignsInTest, [excluded: ["test/support/live_view_test_helpers.ex"]]}, - {Jump.CredoChecks.ConditionalAssertion} - # {Jump.CredoChecks.DoctestIExExamples, - # [ - # derive_test_path: fn filename -> - # filename - # |> String.replace_leading("lib/", "test/") - # |> String.replace_trailing(".ex", "_test.exs") - # end - # ]}, + {Jump.CredoChecks.ConditionalAssertion}, + {Jump.CredoChecks.DoctestIExExamples, + [ + derive_test_path: fn filename -> + filename + |> String.replace_leading("lib/", "test/") + |> String.replace_trailing(".ex", "_test.exs") + end + ]} # {Jump.CredoChecks.ForbiddenFunction, # [ # functions: [ diff --git a/lib/towerops/agents/stats.ex b/lib/towerops/agents/stats.ex index 48df1ff0..2f09194d 100644 --- a/lib/towerops/agents/stats.ex +++ b/lib/towerops/agents/stats.ex @@ -26,6 +26,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> org_id = Ecto.UUID.generate() iex> get_organization_agent_health(org_id) [ %{ @@ -85,6 +86,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> org_id = Ecto.UUID.generate() iex> get_device_assignment_breakdown(org_id) %{ direct: 50, @@ -152,6 +154,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> agent_id = Ecto.UUID.generate() iex> get_agent_metric_stats(agent_id) %{ total_metrics: 1440, @@ -225,6 +228,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> org_id = Ecto.UUID.generate() iex> get_offline_agents(org_id) [ %{id: "uuid", name: "DC2 Agent", last_seen_at: ~U[2026-01-14 10:00:00Z]} @@ -252,6 +256,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> org_id = Ecto.UUID.generate() iex> get_high_load_agents(org_id) [ %{id: "uuid", name: "DC1 Agent", device_count: 75} @@ -284,6 +289,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> org_id = Ecto.UUID.generate() iex> get_unmonitored_devices(org_id) [ %{id: "uuid", name: "Switch-01", site_name: "DC1"} @@ -325,6 +331,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> device_id = Ecto.UUID.generate() iex> get_device_latency_by_agent(device_id, min_checks: 10) [ %{agent_token_id: "uuid-1", avg_latency_ms: 12.5, check_count: 120}, @@ -363,6 +370,7 @@ defmodule Towerops.Agents.Stats do ## Examples + iex> device_id = Ecto.UUID.generate() iex> get_device_assignment_with_latency(device_id) %{ device_id: "uuid", diff --git a/lib/towerops/ecto_types/ip_address.ex b/lib/towerops/ecto_types/ip_address.ex index 2339a333..999e9ab2 100644 --- a/lib/towerops/ecto_types/ip_address.ex +++ b/lib/towerops/ecto_types/ip_address.ex @@ -113,7 +113,7 @@ defmodule Towerops.EctoTypes.IpAddress do ## Examples iex> IpAddress.new("192.168.1.1") - {:ok, %IpAddress{address: "192.168.1.1", version: :ipv4}} + {:ok, %IpAddress{address: "192.168.1.1", version: :ipv4, tuple: {192, 168, 1, 1}}} iex> IpAddress.new("invalid") :error @@ -129,7 +129,7 @@ defmodule Towerops.EctoTypes.IpAddress do ## Examples iex> IpAddress.new!("192.168.1.1") - %IpAddress{address: "192.168.1.1", version: :ipv4} + %IpAddress{address: "192.168.1.1", version: :ipv4, tuple: {192, 168, 1, 1}} iex> IpAddress.new!("invalid") ** (ArgumentError) invalid IP address: "invalid" diff --git a/test/snmpkit/snmp_lib/asn1_test.exs b/test/snmpkit/snmp_lib/asn1_test.exs index abc73f56..5c012cb1 100644 --- a/test/snmpkit/snmp_lib/asn1_test.exs +++ b/test/snmpkit/snmp_lib/asn1_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.ASN1Test do alias SnmpKit.SnmpLib.ASN1 + doctest ASN1 + @moduletag :unit @moduletag :protocol @moduletag :phase_2 diff --git a/test/snmpkit/snmp_lib/host_parser_test.exs b/test/snmpkit/snmp_lib/host_parser_test.exs index 83d49fbe..d44a6b69 100644 --- a/test/snmpkit/snmp_lib/host_parser_test.exs +++ b/test/snmpkit/snmp_lib/host_parser_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.HostParserTest do alias SnmpKit.SnmpLib.HostParser + doctest HostParser + @moduletag :unit @moduletag :host_parser diff --git a/test/snmpkit/snmp_lib/mib/compiler_test.exs b/test/snmpkit/snmp_lib/mib/compiler_test.exs index f07038b7..33f890c2 100644 --- a/test/snmpkit/snmp_lib/mib/compiler_test.exs +++ b/test/snmpkit/snmp_lib/mib/compiler_test.exs @@ -11,6 +11,8 @@ defmodule SnmpKit.SnmpLib.MIB.CompilerTest do alias SnmpKit.SnmpLib.MIB.Compiler alias SnmpKit.SnmpLib.MIB.Parser + doctest Compiler, except: [compile: 1, compile_string: 1, compile_string: 2, load_compiled: 1, compile_all: 1] + # Skip these tests if yecc is not available (requires :parsetools) @moduletag :yecc_required diff --git a/test/snmpkit/snmp_lib/mib/error_test.exs b/test/snmpkit/snmp_lib/mib/error_test.exs index f8a014fe..128d459c 100644 --- a/test/snmpkit/snmp_lib/mib/error_test.exs +++ b/test/snmpkit/snmp_lib/mib/error_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.MIB.ErrorTest do alias SnmpKit.SnmpLib.MIB.Error + doctest Error + describe "new/2" do test "creates error with type and message" do error = Error.new(:syntax_error) diff --git a/test/snmpkit/snmp_lib/mib/registry_test.exs b/test/snmpkit/snmp_lib/mib/registry_test.exs index d5dde353..3a624642 100644 --- a/test/snmpkit/snmp_lib/mib/registry_test.exs +++ b/test/snmpkit/snmp_lib/mib/registry_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.MIB.RegistryTest do alias SnmpKit.SnmpLib.MIB.Registry + doctest Registry, except: [walk_tree: 1] + describe "resolve_name/1" do test "resolves standard MIB names" do assert {:ok, [1, 3, 6, 1, 2, 1, 1, 1]} = Registry.resolve_name("sysDescr") diff --git a/test/snmpkit/snmp_lib/oid_test.exs b/test/snmpkit/snmp_lib/oid_test.exs index 90baa231..77d28909 100644 --- a/test/snmpkit/snmp_lib/oid_test.exs +++ b/test/snmpkit/snmp_lib/oid_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.OIDTest do alias SnmpKit.SnmpLib.OID + doctest OID + @moduletag :unit @moduletag :protocol @moduletag :phase_2 diff --git a/test/snmpkit/snmp_lib/pdu_test.exs b/test/snmpkit/snmp_lib/pdu_test.exs index abdd7ba9..f87c5c33 100644 --- a/test/snmpkit/snmp_lib/pdu_test.exs +++ b/test/snmpkit/snmp_lib/pdu_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.PDUTest do alias SnmpKit.SnmpLib.PDU + doctest PDU + @moduletag :unit @moduletag :protocol @moduletag :phase_1 diff --git a/test/snmpkit/snmp_lib/transport_test.exs b/test/snmpkit/snmp_lib/transport_test.exs index 94b9240b..683c51f1 100644 --- a/test/snmpkit/snmp_lib/transport_test.exs +++ b/test/snmpkit/snmp_lib/transport_test.exs @@ -4,6 +4,8 @@ defmodule SnmpKit.SnmpLib.TransportTest do alias SnmpKit.SnmpLib.Transport + doctest Transport + @moduletag :unit @moduletag :protocol @moduletag :phase_2 diff --git a/test/snmpkit/snmp_lib/types_test.exs b/test/snmpkit/snmp_lib/types_test.exs index 59c5fbee..6ed5955c 100644 --- a/test/snmpkit/snmp_lib/types_test.exs +++ b/test/snmpkit/snmp_lib/types_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpLib.TypesTest do alias SnmpKit.SnmpLib.Types + doctest Types + @moduletag :unit @moduletag :protocol @moduletag :phase_2 diff --git a/test/snmpkit/snmp_mgr/bulk_test.exs b/test/snmpkit/snmp_mgr/bulk_test.exs index 279245b0..d4a13271 100644 --- a/test/snmpkit/snmp_mgr/bulk_test.exs +++ b/test/snmpkit/snmp_mgr/bulk_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpMgr.BulkTest do alias SnmpKit.SnmpMgr.Bulk + doctest Bulk + describe "get_bulk/3 version validation" do test "rejects SNMPv1 with error" do result = Bulk.get_bulk("192.168.1.1", [1, 3, 6, 1, 2, 1, 1], version: :v1) diff --git a/test/snmpkit/snmp_mgr/errors_test.exs b/test/snmpkit/snmp_mgr/errors_test.exs index a9d81fb7..d171525c 100644 --- a/test/snmpkit/snmp_mgr/errors_test.exs +++ b/test/snmpkit/snmp_mgr/errors_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpMgr.ErrorsTest do alias SnmpKit.SnmpMgr.Errors + doctest Errors + describe "code_to_atom/1" do test "converts standard SNMP error codes to atoms" do assert Errors.code_to_atom(0) == :no_error diff --git a/test/snmpkit/snmp_mgr/format_test.exs b/test/snmpkit/snmp_mgr/format_test.exs index 0ce8e25c..d793484c 100644 --- a/test/snmpkit/snmp_mgr/format_test.exs +++ b/test/snmpkit/snmp_mgr/format_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpMgr.FormatTest do alias SnmpKit.SnmpMgr.Format + doctest Format + describe "pretty_print/1 - new functionality" do test "formats 3-tuple results with type-aware formatting" do # Test timeticks formatting (delegates to SnmpKit.SnmpLib.Types) diff --git a/test/snmpkit/snmp_mgr/mib_test.exs b/test/snmpkit/snmp_mgr/mib_test.exs index 1e36a768..de9c833d 100644 --- a/test/snmpkit/snmp_mgr/mib_test.exs +++ b/test/snmpkit/snmp_mgr/mib_test.exs @@ -4,6 +4,8 @@ defmodule SnmpKit.SnmpMgr.MIBTest do alias SnmpKit.SnmpLib.MIB.Parser alias SnmpKit.SnmpMgr.MIB + doctest MIB + setup do # Start the MIB GenServer if not already running case GenServer.whereis(MIB) do diff --git a/test/snmpkit/snmp_mgr/types_test.exs b/test/snmpkit/snmp_mgr/types_test.exs index c63c6d03..13016730 100644 --- a/test/snmpkit/snmp_mgr/types_test.exs +++ b/test/snmpkit/snmp_mgr/types_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpMgr.TypesTest do alias SnmpKit.SnmpMgr.Types + doctest Types + describe "encode_value/2 with automatic type inference" do test "infers string type for printable binary" do assert {:ok, {:string, "Hello World"}} = Types.encode_value("Hello World") diff --git a/test/snmpkit/snmp_mgr/walk_test.exs b/test/snmpkit/snmp_mgr/walk_test.exs index fff6c52e..9dcce155 100644 --- a/test/snmpkit/snmp_mgr/walk_test.exs +++ b/test/snmpkit/snmp_mgr/walk_test.exs @@ -3,6 +3,8 @@ defmodule SnmpKit.SnmpMgr.WalkTest do alias SnmpKit.SnmpMgr.Walk + doctest Walk + # Test helpers to mock Core module behavior defmodule CoreMock do @moduledoc false diff --git a/test/towerops/accounts/hibp_test.exs b/test/towerops/accounts/hibp_test.exs index 09460ff5..13296a08 100644 --- a/test/towerops/accounts/hibp_test.exs +++ b/test/towerops/accounts/hibp_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Accounts.HIBPTest do alias Towerops.Accounts.HIBP + doctest HIBP, except: [check_password: 1] + describe "check_password/1 with non-binary input" do test "returns {:ok, :unknown} for nil" do assert {:ok, :unknown} = HIBP.check_password(nil) diff --git a/test/towerops/accounts/passwords_test.exs b/test/towerops/accounts/passwords_test.exs new file mode 100644 index 00000000..183a2d67 --- /dev/null +++ b/test/towerops/accounts/passwords_test.exs @@ -0,0 +1,36 @@ +defmodule Towerops.Accounts.PasswordsTest do + use ExUnit.Case, async: true + + alias Towerops.Accounts.Passwords + + # The module's @doc examples reference undefined variables (`user`, `url`) and + # use `...` placeholder syntax, which are not valid standalone doctests. + # Manual tests cover each function instead. + # doctest Towerops.Accounts.Passwords + + alias Towerops.Accounts.User + + describe "change_user_password/3" do + test "returns an Ecto.Changeset with default empty attrs" do + user = %User{} + + assert %Ecto.Changeset{data: %User{}} = + Passwords.change_user_password(user) + end + + test "returns an Ecto.Changeset with provided attrs" do + user = %User{email: "test@example.com"} + attrs = %{password: "new-valid-password-123!", password_confirmation: "new-valid-password-123!"} + + assert %Ecto.Changeset{data: %User{}} = + Passwords.change_user_password(user, attrs) + end + + test "returns an Ecto.Changeset with opts" do + user = %User{email: "test@example.com"} + attrs = %{password: "new-valid-password-123!", password_confirmation: "new-valid-password-123!"} + + assert %Ecto.Changeset{} = Passwords.change_user_password(user, attrs, []) + end + end +end diff --git a/test/towerops/accounts_test.exs b/test/towerops/accounts_test.exs index cc3f8987..9e8946ed 100644 --- a/test/towerops/accounts_test.exs +++ b/test/towerops/accounts_test.exs @@ -10,6 +10,8 @@ defmodule Towerops.AccountsTest do alias Towerops.GeoIP.Block alias Towerops.GeoIP.Location + doctest Accounts + describe "get_user_by_email/1" do test "does not return the user if the email does not exist" do refute Accounts.get_user_by_email("unknown@example.com") diff --git a/test/towerops/admin/audit_logger_test.exs b/test/towerops/admin/audit_logger_test.exs index 07e9e5a6..60101dc5 100644 --- a/test/towerops/admin/audit_logger_test.exs +++ b/test/towerops/admin/audit_logger_test.exs @@ -6,6 +6,8 @@ defmodule Towerops.Admin.AuditLoggerTest do alias Towerops.Admin.AuditLog alias Towerops.Admin.AuditLogger + doctest AuditLogger + setup do actor = user_fixture() target = user_fixture() diff --git a/test/towerops/admin_test.exs b/test/towerops/admin_test.exs index 6548e682..0aa00e9d 100644 --- a/test/towerops/admin_test.exs +++ b/test/towerops/admin_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.AdminTest do alias Towerops.Admin alias Towerops.Organizations.Organization + doctest Admin, except: [delete_user: 3, delete_organization: 3, create_audit_log: 1] + describe "create_audit_log/1" do test "creates audit log with valid attributes" do superuser = user_fixture(%{superuser: true}) diff --git a/test/towerops/agents/agent_token_test.exs b/test/towerops/agents/agent_token_test.exs index 962b612a..2c215ba5 100644 --- a/test/towerops/agents/agent_token_test.exs +++ b/test/towerops/agents/agent_token_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Agents.AgentTokenTest do alias Towerops.Agents.AgentToken + doctest AgentToken + describe "build_token/3" do test "generates a token with 48 bytes of entropy" do org_id = Ecto.UUID.generate() diff --git a/test/towerops/agents/stats_test.exs b/test/towerops/agents/stats_test.exs index 8c50a5d2..9584ad3b 100644 --- a/test/towerops/agents/stats_test.exs +++ b/test/towerops/agents/stats_test.exs @@ -17,6 +17,8 @@ defmodule Towerops.Agents.StatsTest do alias Towerops.Snmp.Sensor alias Towerops.Snmp.SensorReading + doctest Stats + describe "get_organization_agent_health/1" do test "returns empty list for organization with no agents" do user = user_fixture() diff --git a/test/towerops/agents_test.exs b/test/towerops/agents_test.exs index 7e395f1a..52834dae 100644 --- a/test/towerops/agents_test.exs +++ b/test/towerops/agents_test.exs @@ -9,6 +9,8 @@ defmodule Towerops.AgentsTest do alias Towerops.Agents.AgentCache alias Towerops.Agents.AgentToken + doctest Agents + setup do user = user_fixture() diff --git a/test/towerops/api_tokens_test.exs b/test/towerops/api_tokens_test.exs index ce998cda..9b9ec817 100644 --- a/test/towerops/api_tokens_test.exs +++ b/test/towerops/api_tokens_test.exs @@ -8,6 +8,8 @@ defmodule Towerops.ApiTokensTest do alias Towerops.ApiTokens alias Towerops.ApiTokens.ApiToken + doctest ApiTokens + describe "create_api_token/1" do setup do user = user_fixture() diff --git a/test/towerops/billing_test.exs b/test/towerops/billing_test.exs index 4e9e111e..cdc53f6a 100644 --- a/test/towerops/billing_test.exs +++ b/test/towerops/billing_test.exs @@ -12,6 +12,8 @@ defmodule Towerops.BillingTest do alias Towerops.Organizations.Organization alias Towerops.Settings.ApplicationSetting + doctest Billing + setup do user = user_fixture() organization = organization_fixture(user.id) diff --git a/test/towerops/devices/firmware_test.exs b/test/towerops/devices/firmware_test.exs index 54ee5e2d..5b3f50d0 100644 --- a/test/towerops/devices/firmware_test.exs +++ b/test/towerops/devices/firmware_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.Devices.FirmwareTest do alias Towerops.Devices.Firmware alias Towerops.Snmp.Device, as: SnmpDevice + doctest Firmware + describe "upsert_firmware_release/1" do test "creates a new firmware release" do attrs = %{ diff --git a/test/towerops/devices/mikrotik_backups/differ_test.exs b/test/towerops/devices/mikrotik_backups/differ_test.exs index efb198f4..02e52a11 100644 --- a/test/towerops/devices/mikrotik_backups/differ_test.exs +++ b/test/towerops/devices/mikrotik_backups/differ_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Devices.MikrotikBackups.DifferTest do alias Towerops.Devices.MikrotikBackups.Differ + doctest Differ + describe "mask_sensitive_data/1" do test "masks passwords in user set commands" do config = "/user set admin password=SuperSecret123" diff --git a/test/towerops/devices/version_comparator_test.exs b/test/towerops/devices/version_comparator_test.exs index cd193a58..8c7de33b 100644 --- a/test/towerops/devices/version_comparator_test.exs +++ b/test/towerops/devices/version_comparator_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Devices.VersionComparatorTest do alias Towerops.Devices.VersionComparator + doctest VersionComparator + describe "compare/2" do test "returns :eq for equal versions" do assert VersionComparator.compare("7.14.1", "7.14.1") == :eq diff --git a/test/towerops/devices_test.exs b/test/towerops/devices_test.exs index a5e302eb..ed6d8c76 100644 --- a/test/towerops/devices_test.exs +++ b/test/towerops/devices_test.exs @@ -6,6 +6,8 @@ defmodule Towerops.EquipmentTest do alias Towerops.Devices alias Towerops.Devices.Device + doctest Devices + describe "device" do import Towerops.AccountsFixtures diff --git a/test/towerops/ecto_types/ip_address_test.exs b/test/towerops/ecto_types/ip_address_test.exs index 501896da..567ceeec 100644 --- a/test/towerops/ecto_types/ip_address_test.exs +++ b/test/towerops/ecto_types/ip_address_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.EctoTypes.IpAddressTest do alias Towerops.EctoTypes.IpAddress + doctest IpAddress + describe "type/0" do test "returns :string" do assert IpAddress.type() == :string diff --git a/test/towerops/ecto_types/mac_address_test.exs b/test/towerops/ecto_types/mac_address_test.exs index 30775156..8e01102f 100644 --- a/test/towerops/ecto_types/mac_address_test.exs +++ b/test/towerops/ecto_types/mac_address_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.EctoTypes.MacAddressTest do alias Towerops.EctoTypes.MacAddress + doctest MacAddress + describe "type/0" do test "returns :string" do assert MacAddress.type() == :string diff --git a/test/towerops/ecto_types/snmp_oid_test.exs b/test/towerops/ecto_types/snmp_oid_test.exs index ceae7f80..520e928f 100644 --- a/test/towerops/ecto_types/snmp_oid_test.exs +++ b/test/towerops/ecto_types/snmp_oid_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.EctoTypes.SnmpOidTest do alias Towerops.EctoTypes.SnmpOid + doctest SnmpOid + describe "type/0" do test "returns :string" do assert SnmpOid.type() == :string diff --git a/test/towerops/gaiia/subscriber_matching_test.exs b/test/towerops/gaiia/subscriber_matching_test.exs index 7b6237a4..0ee34837 100644 --- a/test/towerops/gaiia/subscriber_matching_test.exs +++ b/test/towerops/gaiia/subscriber_matching_test.exs @@ -11,6 +11,8 @@ defmodule Towerops.Gaiia.SubscriberMatchingTest do alias Towerops.Gaiia.SubscriberMatching alias Towerops.Repo + doctest SubscriberMatching, except: [normalize_mac: 1] + setup do user = user_fixture() org = organization_fixture(user.id) diff --git a/test/towerops/gaiia_test.exs b/test/towerops/gaiia_test.exs index 36a1db57..d187d6f9 100644 --- a/test/towerops/gaiia_test.exs +++ b/test/towerops/gaiia_test.exs @@ -8,6 +8,8 @@ defmodule Towerops.GaiiaTest do alias Towerops.Gaiia alias Towerops.Snmp.Device + doctest Gaiia + setup do user = user_fixture() org = organization_fixture(user.id) diff --git a/test/towerops/mobile_sessions_test.exs b/test/towerops/mobile_sessions_test.exs index 4b61f87f..c626ca1f 100644 --- a/test/towerops/mobile_sessions_test.exs +++ b/test/towerops/mobile_sessions_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.MobileSessionsTest do alias Towerops.MobileSessions.MobileSession alias Towerops.MobileSessions.QRLoginToken + doctest MobileSessions + defp valid_session_attrs(user) do %{ user_id: user.id, diff --git a/test/towerops/numeric_test.exs b/test/towerops/numeric_test.exs index 143fcc73..7db0262f 100644 --- a/test/towerops/numeric_test.exs +++ b/test/towerops/numeric_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.NumericTest do alias Towerops.Numeric + doctest Numeric + describe "parse_integer/1" do test "returns {:ok, int} for integer" do assert {:ok, 42} = Numeric.parse_integer(42) diff --git a/test/towerops/organizations/policy_test.exs b/test/towerops/organizations/policy_test.exs index d85dbf1e..31027b8d 100644 --- a/test/towerops/organizations/policy_test.exs +++ b/test/towerops/organizations/policy_test.exs @@ -4,6 +4,8 @@ defmodule Towerops.Organizations.PolicyTest do alias Towerops.Organizations.Membership alias Towerops.Organizations.Policy + doctest Policy + describe "can?/3" do test "owner can do everything" do membership = %Membership{role: :owner} diff --git a/test/towerops/organizations/subscription_limits_test.exs b/test/towerops/organizations/subscription_limits_test.exs index dc374689..28d05343 100644 --- a/test/towerops/organizations/subscription_limits_test.exs +++ b/test/towerops/organizations/subscription_limits_test.exs @@ -9,6 +9,8 @@ defmodule Towerops.Organizations.SubscriptionLimitsTest do alias Towerops.Organizations.SubscriptionLimits alias Towerops.Sites + doctest SubscriptionLimits + describe "device_limit/1" do test "returns 10 for free plan" do assert SubscriptionLimits.device_limit("free") == 10 diff --git a/test/towerops/organizations_test.exs b/test/towerops/organizations_test.exs index 71b2e77c..6073c463 100644 --- a/test/towerops/organizations_test.exs +++ b/test/towerops/organizations_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.OrganizationsTest do alias Towerops.Organizations alias Towerops.Organizations.Organization + doctest Organizations + describe "organizations" do setup do user = user_fixture() diff --git a/test/towerops/settings/application_setting_test.exs b/test/towerops/settings/application_setting_test.exs index 1ba8e1d2..2228e370 100644 --- a/test/towerops/settings/application_setting_test.exs +++ b/test/towerops/settings/application_setting_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Settings.ApplicationSettingTest do alias Towerops.Settings.ApplicationSetting + doctest ApplicationSetting + describe "parse_value/1" do test "returns nil for nil value" do setting = %ApplicationSetting{value: nil, value_type: "string"} diff --git a/test/towerops/settings_test.exs b/test/towerops/settings_test.exs index 756d205a..96b3f7a5 100644 --- a/test/towerops/settings_test.exs +++ b/test/towerops/settings_test.exs @@ -4,6 +4,8 @@ defmodule Towerops.SettingsTest do alias Towerops.Settings alias Towerops.Settings.ApplicationSetting + doctest Settings + # Ensure the migration-seeded setting exists (CI may have stale test DB) setup do if !Settings.get_setting_record("global_default_cloud_poller_id") do diff --git a/test/towerops/snmp/agent_discovery_test.exs b/test/towerops/snmp/agent_discovery_test.exs index 4779e55c..09045101 100644 --- a/test/towerops/snmp/agent_discovery_test.exs +++ b/test/towerops/snmp/agent_discovery_test.exs @@ -17,6 +17,8 @@ defmodule Towerops.Snmp.AgentDiscoveryTest do alias Towerops.Snmp.AgentDiscovery alias Towerops.Snmp.Device, as: DiscoveredDevice + doctest AgentDiscovery, except: [process_agent_discovery: 2] + describe "process_agent_discovery/2 — failure paths" do test "empty oid_values returns :agent_collected_no_data" do device = DevicesFixtures.device_fixture() diff --git a/test/towerops/snmp/client_test.exs b/test/towerops/snmp/client_test.exs index 538c013c..2ca8dcdb 100644 --- a/test/towerops/snmp/client_test.exs +++ b/test/towerops/snmp/client_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.Snmp.ClientTest do alias Towerops.Snmp.Client alias Towerops.Snmp.SnmpMock + doctest Client + # Set up mocks setup :verify_on_exit! diff --git a/test/towerops/snmp/discovery_test.exs b/test/towerops/snmp/discovery_test.exs index 4ae5fbde..b6127513 100644 --- a/test/towerops/snmp/discovery_test.exs +++ b/test/towerops/snmp/discovery_test.exs @@ -13,6 +13,8 @@ defmodule Towerops.Snmp.DiscoveryTest do alias Towerops.Snmp.Sensor alias Towerops.Snmp.SnmpMock + doctest Discovery + setup :verify_on_exit! # Stub get_multiple and get to provide generic fallbacks diff --git a/test/towerops/snmp/sensor_scale_test.exs b/test/towerops/snmp/sensor_scale_test.exs index 59079425..741a9655 100644 --- a/test/towerops/snmp/sensor_scale_test.exs +++ b/test/towerops/snmp/sensor_scale_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.Snmp.SensorScaleTest do alias Towerops.Snmp.SensorScale + doctest SensorScale + describe "normalize/2 — temperature" do test "passes plausible whole-degree readings through unchanged" do assert SensorScale.normalize("temperature", 36.0) == 36.0 diff --git a/test/towerops/snmp_test.exs b/test/towerops/snmp_test.exs index dd986cbb..2748a1c7 100644 --- a/test/towerops/snmp_test.exs +++ b/test/towerops/snmp_test.exs @@ -19,6 +19,8 @@ defmodule Towerops.SnmpTest do alias Towerops.Snmp.WirelessClient alias Towerops.Snmp.WirelessClientReading + doctest Snmp + setup do user = user_fixture() {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) diff --git a/test/towerops/topology/lldp_test.exs b/test/towerops/topology/lldp_test.exs index 836a86c2..e4e4f540 100644 --- a/test/towerops/topology/lldp_test.exs +++ b/test/towerops/topology/lldp_test.exs @@ -7,6 +7,8 @@ defmodule Towerops.Topology.LldpTest do alias Towerops.Topology.Lldp alias Towerops.Topology.Lldp.Parser + doctest Lldp + setup :verify_on_exit! setup do diff --git a/test/towerops/url_validator_test.exs b/test/towerops/url_validator_test.exs index 6e47dde0..e2ce8a12 100644 --- a/test/towerops/url_validator_test.exs +++ b/test/towerops/url_validator_test.exs @@ -3,6 +3,8 @@ defmodule Towerops.URLValidatorTest do alias Towerops.URLValidator + doctest URLValidator + describe "validate/1" do test "accepts valid https URL" do assert :ok = URLValidator.validate("https://example.com") diff --git a/test/towerops/workers/firmware_version_fetcher_worker_test.exs b/test/towerops/workers/firmware_version_fetcher_worker_test.exs index e4073736..69714707 100644 --- a/test/towerops/workers/firmware_version_fetcher_worker_test.exs +++ b/test/towerops/workers/firmware_version_fetcher_worker_test.exs @@ -4,6 +4,8 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorkerTest do alias Towerops.Devices.Firmware alias Towerops.Workers.FirmwareVersionFetcherWorker + doctest FirmwareVersionFetcherWorker + describe "perform/1" do test "returns :ok and inserts a release on a valid RSS response" do Req.Test.stub(FirmwareVersionFetcherWorker, fn conn -> diff --git a/test/towerops_web/helpers/status_helpers_test.exs b/test/towerops_web/helpers/status_helpers_test.exs index 4ef98fd3..c1a401cb 100644 --- a/test/towerops_web/helpers/status_helpers_test.exs +++ b/test/towerops_web/helpers/status_helpers_test.exs @@ -9,6 +9,8 @@ defmodule ToweropsWeb.Helpers.StatusHelpersTest do alias Towerops.Sites alias ToweropsWeb.Helpers.StatusHelpers + doctest StatusHelpers + describe "status_emoji/1" do test "returns green for nil organization" do assert StatusHelpers.status_emoji(nil) == "🟢" diff --git a/test/towerops_web/helpers/time_helpers_test.exs b/test/towerops_web/helpers/time_helpers_test.exs index acc42f16..bc5d2725 100644 --- a/test/towerops_web/helpers/time_helpers_test.exs +++ b/test/towerops_web/helpers/time_helpers_test.exs @@ -3,6 +3,8 @@ defmodule ToweropsWeb.TimeHelpersTest do alias ToweropsWeb.TimeHelpers + doctest TimeHelpers + describe "to_user_timezone/2" do test "returns shifted datetime and abbreviation for known timezone" do datetime = ~U[2026-01-15 14:34:00Z] diff --git a/test/towerops_web/permissions_test.exs b/test/towerops_web/permissions_test.exs index 3861d565..5af1cc0a 100644 --- a/test/towerops_web/permissions_test.exs +++ b/test/towerops_web/permissions_test.exs @@ -9,6 +9,8 @@ defmodule ToweropsWeb.PermissionsTest do alias Towerops.Repo alias ToweropsWeb.Permissions + doctest Permissions, except: [can?: 3, owner?: 1, admin?: 1] + describe "can?/3 with superuser" do setup do user = user_fixture(%{is_superuser: true})