Commit graph

1316 commits

Author SHA1 Message Date
46e71019de
test: expand coverage for Layouts, DeviceCache, Components and others 2026-04-23 16:36:01 -05:00
FluxCD
006f9ab98b chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776979875-4173125 [skip ci] 2026-04-23 21:31:21 +00:00
41731257e6
test: cover auth LiveViews, PacketReplay, ShutdownHandler and more 2026-04-23 16:30:51 -05:00
FluxCD
3ab167777e chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776979144-16d2e92 [skip ci] 2026-04-23 21:22:15 +00:00
16d2e929c0
test: push coverage to 70% with more CoreComponents and PostgresNotifier
- CoreComponents.input/1: expanded coverage to include the select,
  textarea, generic-text, and unchecked-checkbox branches, plus
  error-vs-no-error border styling.
- PostgresNotifier: handle_info forwards pg_notify payload to
  Aprsme.PubSub and ignores unrelated messages.

Coverage 69.56 → 70.11%.
2026-04-23 16:18:04 -05:00
FluxCD
5363b2cb69 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776979015-fa893dd [skip ci] 2026-04-23 21:17:22 +00:00
fa893dd12e
test: cover ErrorHTML, Layouts, MapLive.Components, CoreComponents, Accounts
- ErrorHTML: explicit 400 path + 401/403/999 delegation.
- Layouts.body_class/1 returns the expected light/dark theme classes.
- MapLive.Components: map_container + slideover_panel exercising all
  connection_status variants, loading state, tracked_callsign clear
  button, and view-mode radios.
- CoreComponents: icon (found + fallback), button, label, error,
  flash (info + error + close=false), checkbox input, JS composers.
- Accounts: get_user_by_email{_and_password}, get_user!, register_user
  happy-path + error paths, change_* changesets, session-token
  round-trip.

Refactor: DeviceIdentification.maybe_refresh_devices splits its nested
logic into fetch_most_recent_device/0, to_datetime/1, and
refresh_if_stale/2 — each a multi-clause function matching on shape.

Coverage 68.28 → 69.56%.
2026-04-23 16:16:31 -05:00
FluxCD
6edc401168 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776975272-ab0204f [skip ci] 2026-04-23 20:14:38 +00:00
ab0204f3dc
test: add StreamData properties for Aprsme.GeoUtils
Four properties exercise haversine_distance / significant_movement?:

- non-negativity across any in-range coordinate pair
- symmetry: d(a, b) == d(b, a) within a tight tolerance
- identity: d(p, p) == 0.0
- significance agrees with (haversine > threshold) for any integer
  threshold in 1..1000

Total: +4 properties, coverage stays clean (dialyzer: 0 new errors).
2026-04-23 15:14:12 -05:00
FluxCD
8edc4bb4c7 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776974614-c90a76d [skip ci] 2026-04-23 20:04:00 +00:00
c90a76df04
refactor: CoordinateUtils.get_coordinates_from_mic_e uses guarded clauses
- get_coordinates_from_mic_e: replace two inline `if direction == ...`
  rebinds with a reusable apply_hemisphere_sign/3 helper; the final
  range check becomes maybe_return_coords/2 with a guarded clause that
  yields {lat, lon} or {nil, nil}.
- has_position_data?: the boolean short-circuit collapses from an
  explicit if/else to a single `or` expression.

All 37 CoordinateUtils tests (4 properties) still pass.
2026-04-23 15:03:09 -05:00
FluxCD
d07758a3f4 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776974278-48943cd [skip ci] 2026-04-23 19:58:23 +00:00
48943cdc52
refactor: Is.get_status pattern-matches on process presence
The original get_status/0 had a nested case/try that duplicated the
"disconnected" status map across two branches. Split into:

- status_from/1 with nil + is_pid heads for the "no GenServer" and
  "GenServer alive" paths. The alive path isolates the catch :exit, _
  fallback for a non-responding process.
- disconnected_status/1 builds the shared status map once, parameterised
  on the default server string to preserve the original branch-specific
  fallback behavior.

Removes ~20 duplicated lines; all 61 Is tests still pass.
2026-04-23 14:57:38 -05:00
FluxCD
f86c185f27 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776974190-401d43b [skip ci] 2026-04-23 19:57:17 +00:00
401d43be62
refactor: pattern-match LeaderElection init and cluster-status dispatch
- get_cluster_aprs_status: fetch_cluster_status/1 dispatches on the
  clustering flag — true fans out cluster-wide, false goes straight to
  the local Aprsme.Is status.
- init/1: extract schedule_initial_election/1 with true/false heads.
  The clustered branch sets up the check-and-backstop timers; the
  non-clustered branch queues an immediate election. Makes the two
  startup paths obvious from the function signatures.

No behavior change; all 17 LeaderElection tests still pass.
2026-04-23 14:56:07 -05:00
FluxCD
f943d887c5 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776974081-20d4637 [skip ci] 2026-04-23 19:55:30 +00:00
20d463794b
test: cover AprsmeWeb.Gettext helpers
- supported_locales/0 returns the declared ~w(en es de fr) list.
- put_locale/1 sets the Gettext process locale for each supported
  value and raises FunctionClauseError for unsupported input.

3 tests, async:false because they mutate process-wide Gettext state.
2026-04-23 14:54:16 -05:00
FluxCD
2b43e5b2a8 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776974000-cd1e577 [skip ci] 2026-04-23 19:53:48 +00:00
cd1e5771af
refactor: pattern-match Aprsme.Encoding helpers
- encoding_info/1 (binary clause): extract build_encoding_info/2 with
  true/false heads on String.valid?/1, so the valid-UTF-8 and invalid
  branches each own their map literal.
- try_utf8_conversion/1: convert_to_utf8/2 dispatches on String.valid?/1
  so the latin1 → UTF-8 fallback is a function head, not an inline if.

No behavior change; all 34 Encoding tests still pass.
2026-04-23 14:52:59 -05:00
FluxCD
1e55d106a0 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776973825-0cbe93f [skip ci] 2026-04-23 19:50:52 +00:00
0cbe93f8db
refactor: MobileChannel callsign search pattern via function dispatch
build_search_pattern/1 picks between SQL-wildcard (when the query
contains `*`) and prefix-match (SSID-friendly) forms via two function
heads instead of an inline `if`. The transform is now isolated and
obviously boolean-dispatched at the call site.
2026-04-23 14:50:03 -05:00
FluxCD
5a8f30916e chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776973130-9053eef [skip ci] 2026-04-23 19:39:17 +00:00
9053eef2c6
refactor: AprsSymbol.normalize_symbol_table pattern-matches on input
- Three-way cond (known-table / overlay-capable char / fallback) becomes
  three function heads: a guard-matched clause for the canonical
  "/"/"\\"/"]" tables, an is_binary clause that decides via regex match
  whether the input is a single alphanumeric overlay character, and a
  catch-all fallback.
2026-04-23 14:38:26 -05:00
FluxCD
2e5034f8c3 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776972493-a85f74e [skip ci] 2026-04-23 19:28:58 +00:00
a85f74ec3f
refactor: leadership_change handler pattern-matches instead of cond
Cluster.ConnectionManager.handle_info({:leadership_change, ...}) used
a cond on the (became_leader, node, connection_started) triple. Split
into handle_leadership_change/3 with three clauses:

- became_leader=true, us=true, not already started → start APRS-IS
- became_leader=false, us=true, already started → stop APRS-IS
- everything else → no-op

Makes the three state transitions visible in the function heads and
eliminates one more cond from the codebase.
2026-04-23 14:27:49 -05:00
FluxCD
c1c7e10d26 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776972406-69152e8 [skip ci] 2026-04-23 19:27:12 +00:00
69152e86b3
refactor: split PacketProducer.handle_cast into pattern-matched heads
The original handle_cast had nested `if`s: outer branch on demand > 0,
inner branch on buffer-over-capacity. Split into:

- handle_cast with a `when demand > 0` guard for the hot path that
  skips the buffer entirely.
- A fallback clause that computes whether the new size would overflow
  and delegates to buffer_packet/3.
- buffer_packet/3 has two clauses — one for the drop-oldest path
  (with telemetry + warning) and one for the simple append path. Both
  share the final `maybe_activate_backpressure |> reply_noemit` step.

All 19 existing PacketProducer tests pass; dialyzer stays clean.
2026-04-23 14:26:23 -05:00
FluxCD
7ce011bddf chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776972295-c910f9a [skip ci] 2026-04-23 19:25:21 +00:00
c910f9a432
refactor: split if/else in Accounts.User password helpers
- do_hash_password/3: move the changeset.valid? branch out of the
  `if` into apply_hash/3, dispatched on the boolean. The bcrypt 72-byte
  cap and plaintext-scrubbing steps now live in one clear function head.
- validate_current_password/2: dispatch on valid_password?/2 via
  check_current_password/2 so the add_error branch is its own clause.

No behavior change; all 24 Accounts tests still pass and dialyzer stays
clean.
2026-04-23 14:24:29 -05:00
FluxCD
edd5a8b30c chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776972222-1d68868 [skip ci] 2026-04-23 19:24:08 +00:00
1d68868d27
refactor: pattern-match InfoLive.Show path parsing + add tests
- parse_path_element_with_link splits its fat `if`/or-chain into three
  focused helpers: linkable_callsign?/1 (regex + alias check),
  path_alias?/1 (four String.starts_with guards), and
  classify_path_element/2 (link vs. text dispatched on the boolean).
- display_for_element/2 chooses the callsign form with/without the
  asterisk via two function heads instead of an inline `if`.

Adds 7 tests covering the parse_path_with_links/1 public API — plain
callsigns, heard-via asterisk preservation, non-linkable aliases
(WIDE/TRACE/RELAY/TCPIP), q-constructs, whitespace trimming, and mixed
paths.
2026-04-23 14:23:16 -05:00
FluxCD
bcbaddc18b chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776972102-282d3c1 [skip ci] 2026-04-23 19:22:10 +00:00
282d3c1ccb
refactor: pattern-match ShutdownHandler + add tests
- handle_call(:shutdown, _, state): split into a shutting_down=true
  fast-path clause and a normal initiate_shutdown clause. No more
  `if state.shutting_down` inside the callback body.
- terminate/2: extract graceful_shutdown_needed?/1 (four function
  heads on the reason tag) and maybe_graceful_drain/2 (guarded on
  state.shutting_down) so the shutdown side-effects are isolated to
  a single, pattern-matched entry point.

Adds 4 unit tests for the pure callback paths
(shutting_down?, shutdown-already-in-progress, EXIT pass-through,
rescue fallback on unavailable GenServer).
2026-04-23 14:21:15 -05:00
FluxCD
dd0fe397f1 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776971969-fc5e914 [skip ci] 2026-04-23 19:20:17 +00:00
fc5e91479b
refactor: pattern-match CoreComponents.safe_row_id + CallsignController
- CoreComponents.safe_row_id: four function heads dispatch on the row
  shape (atom-key map, string-key map, other map fallback, non-map)
  instead of a cond with Map.has_key? checks.
- Api.V1.CallsignController.validate_callsign: check_callsign_format/2
  splits the validation success/failure branches into two clauses; the
  binary-vs-everything-else dispatch stays in validate_callsign/1.

Adds 5 integration tests for the CallsignController covering invalid,
not-found, success, case-normalization, and length-limit paths. The
test file is async:false because it shares the rate-limiter ETS with
other API tests and could otherwise trip the 100/min per-IP cap.
2026-04-23 14:18:30 -05:00
FluxCD
ed993aa4de chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776971587-d879b54 [skip ci] 2026-04-23 19:13:36 +00:00
d879b54fd4
refactor: replace more cond expressions with guarded clauses
- CoordinateUtils.normalize_longitude / normalize_latitude: recursion
  and clamping move into the function head via numeric guards.
- Shared.PacketUtils.map_label: dispatch on data_type + fallback via
  multi-clause helpers (map_label_for/2, prefer_name/2) instead of a
  three-branch cond with inner `if`s.
- MapLive.DataBuilder.get_received_at: pattern-match the atom- and
  string-key packet shapes in the function head.

No behavior change; all 1567 tests and 27 property checks still pass,
dialyzer remains clean.
2026-04-23 14:12:45 -05:00
FluxCD
8d777b2cf8 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776971420-35bd098 [skip ci] 2026-04-23 19:10:58 +00:00
35bd098b30
refactor: more pattern matching + drop unreachable get_field_value clause
- Aprsme.Packet.put_phg_fields: dispatch on the shape of the phg value
  (map / 4-char binary / anything else) via put_phg_fields_for/2.
- Aprsme.Packet.get_field_value: remove the catch-all nil clause. After
  the put_phg_fields refactor, dialyzer can prove every call site passes
  a map and flagged the fallback as unreachable — so it's gone, and
  a future mistyped caller now fails loudly instead of silently.
- LogSanitizer.sanitize_map: extract redact_field/2 for readability.
- DeviceIdentification.pattern_matches?: match_pattern/3 dispatched on
  String.contains?/2 keeps the rescue tight around the regex path.
- InfoLive.Show: get_received_at pattern-matches on key shape;
  format_distance splits locale × range via four format_*_distance
  helpers; calculate_course pipes through normalize_bearing/1.

Adds 15 tests exercising the InfoLive.Show helpers (imperial vs. metric
formatting, cardinal bearings, haversine symmetry, Decimal inputs).
Coverage 67.43 → 67.72%.
2026-04-23 14:09:53 -05:00
FluxCD
bb080fd1dd chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776971001-ee02769 [skip ci] 2026-04-23 19:04:11 +00:00
ee02769d38
refactor: pattern-match in HealthCheck, EncodingUtils, and StatusLive helpers
- HealthCheck.check_health(:readiness): collapse the 3-branch cond into
  readiness_status/2 dispatched on (health_status, shutting_down?).
- HealthCheck.shutting_down?: the whereis + alive? + try/catch nest
  becomes a small pipeline of function heads (ask_shutting_down?/1 +
  ask_if_alive/2), with the catch isolated to the single place it fires.
- EncodingUtils.sanitize_string_fields and sanitize_nested_map shared a
  three-branch atom-or-string key lookup. Extract update_existing_key/3
  + first_present_key/3 + nil_aware/1 helpers; the original functions
  become two-liners.
- StatusLive.Index.format_uptime: splits the cond into
  format_uptime_parts/4 clauses with numeric guards.
- StatusLive.Index.calculate_health_score: struct-shape pattern match
  on %{connected: false} / %{uptime_seconds: s} guards replaces the cond.
- StatusLive.Index.format_time_ago: pipe the diff through
  format_seconds_ago/1 with four clauses.

Adds tests for the four public StatusLive.Index helpers
(format_uptime, format_time_ago, get_health_description, format_number).
Coverage 67.29 → 67.43%.
2026-04-23 14:02:50 -05:00
FluxCD
c0afd21620 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776970743-564d21b [skip ci] 2026-04-23 18:59:29 +00:00
564d21bb26
refactor: pattern-match in TimeHelpers.to_datetime and PageController
- TimeHelpers.to_datetime: `cond` with match?/2 guards becomes five
  function heads dispatched by input type — DateTime passes through,
  NaiveDateTime anchors to UTC, integer is a millisecond Unix epoch,
  binary tries ISO 8601, everything else is nil.
- PageController.health: the three-branch `cond` + inner `if db_healthy`
  becomes a chain of small respond_* helpers, each pattern-matched on a
  single axis (health_status, shutting_down?, db_healthy?). db_healthy?/0
  isolates the rescue.
- format_uptime splits the cond into four format_uptime_parts/4 clauses.

Adds tests for the PageController actions (health 200 / 503-draining,
ready, sitemap.xml, .well-known/api-catalog, status.json). Coverage
66.81 → 67.29%.
2026-04-23 13:58:42 -05:00
FluxCD
73342df543 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776970532-7db7867 [skip ci] 2026-04-23 18:55:57 +00:00
7db78675a2
refactor: collapse nested if/case into pattern-matched helpers
- SharedPacketHandler.handle_packet_update: dispatch on filter-result,
  and use maybe_enrich/2 dispatched on the enrich? boolean instead of
  an inner `if`. lookup_device_info/1 is now a trio of function heads.
- Cluster.Topology.child_spec: build_spec/3 dispatches on
  (cluster_enabled?, topologies) tuples — no more nested `if`.
- Cluster.PacketDistributor.distribute_packet: maybe_broadcast/2
  dispatches on the leader-and-enabled check; the non-leader / disabled
  paths return :ok explicitly instead of relying on an `if` expression's
  implicit nil.

Adds tests for SharedPacketHandler (filter/enrich/match paths,
callsign_filter + callsign_and_weather_filter factories) and extends
Cluster.Topology tests to cover the nil-topology and opts-merge cases.
Coverage 66.41 → 66.81%.
2026-04-23 13:55:11 -05:00
FluxCD
281f99e39e chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776970302-e43107a [skip ci] 2026-04-23 18:54:45 +00:00
e43107a25f
refactor(packet_processor): split cond/if into multi-clause helpers
- render_for_zoom/3: zoom ≤ 8 uses heatmap; high zoom with marker_data
  pushes to the client; high zoom + nil marker_data is a no-op. Each
  branch is now a separate function head.
- push_new_packet/3: a boolean-dispatched pair replaces the popup-open
  conditional on the push_event payload.
- prepare_packet_state: the two rebinding `if`s turn into a pipeline
  through prune_if_over_cap/1 (pattern-matched on map_size/1) and
  build_marker_data/5 with a zoom ≤ 8 short-circuit clause, plus
  maybe_tag_convert_from/3 for the replacement-marker tag.
- moved_significantly?/3: the duplicated guard check between
  dispatch_visibility and batch_dispatch collapses into one helper that
  pattern-matches on the coordinate tuple returned by CoordinateUtils.

Adds extra tests covering the new significance / stale-coords branches
and the connection card LiveComponent render paths. Coverage 65.89 → 66.41%.
2026-04-23 13:51:17 -05:00
FluxCD
7e47966f67 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776969983-aa0c6e6 [skip ci] 2026-04-23 18:46:49 +00:00
aa0c6e6566
refactor: pattern-match in DeviceCache and DatabaseMetrics + add tests
- DeviceCache.pattern_matches?: replace a 3-branch `cond` with a
  two-clause `case` on `String.contains?(pattern, "?")`. The old `*`
  branch was dead code (it did the same exact-match compare as the
  fallback), so it's removed.
- Telemetry.DatabaseMetrics.collect_postgres_metrics: dispatch on
  environment atom via multi-clause private functions instead of
  `if Application.get_env(...) == :test`.

New tests:
- DeviceCache wildcard/exact lookup paths exercised via a seeded cache.
- MobileUserSocket connect/3 for x_headers/peer_data/empty info and
  rate-limit deny.
- DatabaseMetrics pool-metrics emission captured via :telemetry handler
  and the :test-env short-circuit.
2026-04-23 13:46:00 -05:00
FluxCD
fa970b5637 chore: update aprs.me image to git.mcintire.me/graham/aprs.me:main-1776969532-c5a82b7 [skip ci] 2026-04-23 18:39:19 +00:00