defmodule Mv.Smtp.ConfigBuilderTest do @moduledoc """ Unit tests for Mv.Smtp.ConfigBuilder.build_opts/1. Ensures the single source of truth for SMTP opts correctly handles: - Port 587 (TLS): sockopts must NOT contain :verify (gen_tcp rejects it). - Port 465 (SSL): sockopts MUST contain :verify for initial ssl:connect. """ use ExUnit.Case, async: true alias Mv.Smtp.ConfigBuilder describe "build_opts/1" do test "port 587 (TLS): does not include :verify in sockopts" do opts = ConfigBuilder.build_opts( host: "smtp.example.com", port: 587, username: "user", password: "secret", ssl_mode: "tls", verify_mode: :verify_none ) sockopts = Keyword.get(opts, :sockopts, []) refute Keyword.has_key?(sockopts, :verify), "for 587 sockopts must not contain :verify" assert Keyword.get(opts, :tls) == :always assert Keyword.get(opts, :ssl) == false end test "port 465 (SSL): includes :verify in sockopts" do opts = ConfigBuilder.build_opts( host: "smtp.example.com", port: 465, username: "user", password: "secret", ssl_mode: "ssl", verify_mode: :verify_peer ) sockopts = Keyword.get(opts, :sockopts, []) assert Keyword.has_key?(sockopts, :verify), "for 465 sockopts must contain :verify" assert Keyword.get(sockopts, :verify) == :verify_peer assert Keyword.get(opts, :ssl) == true assert Keyword.get(opts, :tls) == :never end test "strips nil values" do opts = ConfigBuilder.build_opts( host: "smtp.example.com", port: 587, username: nil, password: nil, ssl_mode: "tls", verify_mode: :verify_none ) refute Keyword.has_key?(opts, :username) refute Keyword.has_key?(opts, :password) assert Keyword.get(opts, :relay) == "smtp.example.com" end test "includes adapter and required keys" do opts = ConfigBuilder.build_opts( host: "mail.example.com", port: 587, username: "u", password: "p", ssl_mode: "tls", verify_mode: :verify_none ) assert Keyword.get(opts, :adapter) == Swoosh.Adapters.SMTP assert Keyword.get(opts, :relay) == "mail.example.com" assert Keyword.get(opts, :port) == 587 assert Keyword.get(opts, :auth) == :always assert Keyword.get(opts, :tls_options) == [verify: :verify_none] end end end