Compare commits

...

15 Commits

Author SHA1 Message Date
CI
911ba231cd chore: release version v1.91.4 2025-12-30 09:27:37 +00:00
Dmitry Popov
b3053f325d Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-12-30 10:27:06 +01:00
Dmitry Popov
4ab47334fc fix(core): fixed connections create between k-space systems (considered as wh connection) 2025-12-30 10:27:03 +01:00
CI
e163f02526 chore: [skip ci] 2025-12-28 17:02:12 +00:00
CI
9e22dba8f1 chore: release version v1.91.3 2025-12-28 17:02:12 +00:00
Dmitry Popov
9631406def Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-12-28 18:01:43 +01:00
Dmitry Popov
f6ae448c3b chore: update event post 2025-12-28 18:01:39 +01:00
CI
46345ef596 chore: [skip ci] 2025-12-27 22:11:03 +00:00
CI
1625f16c8f chore: release version v1.91.2 2025-12-27 22:11:03 +00:00
Dmitry Popov
b4ef9ae983 fix(core): fixed map scopes updates & logic 2025-12-27 23:10:26 +01:00
CI
3b9c2dd996 chore: [skip ci] 2025-12-25 18:20:20 +00:00
CI
8a0f9a58d0 chore: release version v1.91.1 2025-12-25 18:20:20 +00:00
Dmitry Popov
5fe8caac0d Merge branch 'main' of github.com:wanderer-industries/wanderer 2025-12-25 19:19:47 +01:00
Dmitry Popov
f18f567727 chore: fix blog link styles 2025-12-25 19:19:44 +01:00
CI
91acc49980 chore: [skip ci] 2025-12-24 15:09:40 +00:00
18 changed files with 552 additions and 80 deletions

3
.gitignore vendored
View File

@@ -17,6 +17,9 @@ repomix*
/priv/static/images/
/priv/static/*.js
/priv/static/*.css
/priv/static/*-*.png
/priv/static/*-*.webp
/priv/static/*-*.webmanifest
# Dialyzer PLT files
/priv/plts/

View File

@@ -2,6 +2,34 @@
<!-- changelog -->
## [v1.91.4](https://github.com/wanderer-industries/wanderer/compare/v1.91.3...v1.91.4) (2025-12-30)
### Bug Fixes:
* core: fixed connections create between k-space systems (considered as wh connection)
## [v1.91.3](https://github.com/wanderer-industries/wanderer/compare/v1.91.2...v1.91.3) (2025-12-28)
## [v1.91.2](https://github.com/wanderer-industries/wanderer/compare/v1.91.1...v1.91.2) (2025-12-27)
### Bug Fixes:
* core: fixed map scopes updates & logic
## [v1.91.1](https://github.com/wanderer-industries/wanderer/compare/v1.91.0...v1.91.1) (2025-12-25)
## [v1.91.0](https://github.com/wanderer-industries/wanderer/compare/v1.90.13...v1.91.0) (2025-12-24)

View File

@@ -1001,3 +1001,27 @@ body > div:first-of-type {
.verticalTabsContainer .p-tabview-panel {
flex-grow: 1;
}
/* Blog post CTA links - only in main post content */
.post-content a {
display: inline-block;
background: linear-gradient(135deg, #ec4899 0%, #8b5cf6 100%);
color: white !important;
padding: 0.5rem 1.25rem;
border-radius: 0.5rem;
text-decoration: none !important;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(236, 72, 153, 0.3);
}
.post-content a:hover {
background: linear-gradient(135deg, #db2777 0%, #7c3aed 100%);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(236, 72, 153, 0.4);
}
.post-content a:active {
transform: translateY(0);
box-shadow: 0 2px 10px rgba(236, 72, 153, 0.3);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@@ -56,7 +56,7 @@ defmodule WandererApp.Map.Server.AclsImpl do
end
)
map_update = %{acls: map.acls, scope: map.scope}
map_update = %{acls: map.acls, scope: map.scope, scopes: map.scopes}
WandererApp.Map.update_map(map_id, map_update)
WandererApp.Cache.delete("map_characters-#{map_id}")

View File

@@ -780,17 +780,39 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
to_is_wormhole = to_system_static_info.system_class in @wh_space
wormholes_enabled = :wormholes in scopes
# Wormhole border behavior: if wormholes scope is enabled AND at least one
# system is a wormhole, allow the connection (adds border k-space systems)
# Otherwise: BOTH systems must match the configured scopes
if wormholes_enabled and (from_is_wormhole or to_is_wormhole) do
# At least one system matches (wormhole matches :wormholes, or other matches its scope)
system_matches_any_scope?(from_system_static_info.system_class, scopes) or
system_matches_any_scope?(to_system_static_info.system_class, scopes)
else
# Non-wormhole movement: both systems must match scopes
system_matches_any_scope?(from_system_static_info.system_class, scopes) and
system_matches_any_scope?(to_system_static_info.system_class, scopes)
cond do
# Case 1: Wormhole border behavior - at least one system is a wormhole
# and :wormholes is enabled, allow the connection (adds border k-space systems)
wormholes_enabled and (from_is_wormhole or to_is_wormhole) ->
# At least one system matches (wormhole matches :wormholes, or other matches its scope)
system_matches_any_scope?(from_system_static_info.system_class, scopes) or
system_matches_any_scope?(to_system_static_info.system_class, scopes)
# Case 2: K-space to K-space with :wormholes enabled - check if it's a wormhole connection
# If neither system is a wormhole AND there's no stargate between them, it's a wormhole connection
wormholes_enabled and not from_is_wormhole and not to_is_wormhole ->
# Check if there's a known stargate connection
case find_solar_system_jump(from_solar_system_id, to_solar_system_id) do
{:ok, known_jumps} when known_jumps == [] ->
# No stargate exists - this is a wormhole connection through k-space
true
{:ok, _known_jumps} ->
# Stargate exists - this is NOT a wormhole, check normal scope matching
system_matches_any_scope?(from_system_static_info.system_class, scopes) and
system_matches_any_scope?(to_system_static_info.system_class, scopes)
_ ->
# Error fetching jumps - fall back to scope matching
system_matches_any_scope?(from_system_static_info.system_class, scopes) and
system_matches_any_scope?(to_system_static_info.system_class, scopes)
end
# Case 3: Non-wormhole movement without :wormholes scope
# Both systems must match the configured scopes
true ->
system_matches_any_scope?(from_system_static_info.system_class, scopes) and
system_matches_any_scope?(to_system_static_info.system_class, scopes)
end
else
false
@@ -865,6 +887,44 @@ defmodule WandererApp.Map.Server.ConnectionsImpl do
end
end
@doc """
Check if a connection between two k-space systems is a wormhole connection.
Returns true if:
1. Both systems are k-space (not wormhole space)
2. There is no known stargate between them
This is used to detect wormhole connections through k-space, like when
a player jumps from low-sec to low-sec through a wormhole.
"""
def is_kspace_wormhole_connection?(from_solar_system_id, to_solar_system_id)
when is_nil(from_solar_system_id) or is_nil(to_solar_system_id),
do: false
def is_kspace_wormhole_connection?(from_solar_system_id, to_solar_system_id)
when from_solar_system_id == to_solar_system_id,
do: false
def is_kspace_wormhole_connection?(from_solar_system_id, to_solar_system_id) do
with {:ok, from_info} <- get_system_static_info(from_solar_system_id),
{:ok, to_info} <- get_system_static_info(to_solar_system_id) do
from_is_wormhole = from_info.system_class in @wh_space
to_is_wormhole = to_info.system_class in @wh_space
# Both must be k-space (not wormhole space)
if not from_is_wormhole and not to_is_wormhole do
# Check if there's a known stargate
case find_solar_system_jump(from_solar_system_id, to_solar_system_id) do
{:ok, []} -> true # No stargate = wormhole connection
_ -> false # Stargate exists or error
end
else
false
end
else
_ -> false
end
end
defp get_system_static_info(solar_system_id) do
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
{:ok, system_static_info} when not is_nil(system_static_info) ->

View File

@@ -547,9 +547,24 @@ defmodule WandererApp.Map.Server.SystemsImpl do
# If :wormholes scope is enabled AND old_location is a wormhole,
# allow this system to be added as a border system (so you can see
# where your wormhole exits to)
:wormholes in scopes and
not is_nil(old_location) and
ConnectionsImpl.can_add_location([:wormholes], old_location.solar_system_id)
wormhole_border_from_wh_space =
:wormholes in scopes and
not is_nil(old_location) and
ConnectionsImpl.can_add_location([:wormholes], old_location.solar_system_id)
# Third check: k-space wormhole connection
# If :wormholes scope is enabled AND there's no stargate between the systems,
# this is a wormhole connection through k-space - add both systems
kspace_wormhole_connection =
:wormholes in scopes and
not is_nil(old_location) and
not is_nil(old_location.solar_system_id) and
ConnectionsImpl.is_kspace_wormhole_connection?(
old_location.solar_system_id,
location.solar_system_id
)
wormhole_border_from_wh_space or kspace_wormhole_connection
end
end

View File

@@ -115,7 +115,9 @@
{@post.description}
</h4>
<!--Post Content-->
{raw(@post.body)}
<div class="post-content">
{raw(@post.body)}
</div>
</div>
</div>
<!--/container-->

View File

@@ -3,7 +3,7 @@ defmodule WandererApp.MixProject do
@source_url "https://github.com/wanderer-industries/wanderer"
@version "1.91.0"
@version "1.91.4"
def project do
[

View File

@@ -1,62 +1,42 @@
%{
title: "Event: Christmas Giveaway Challenge",
title: "Event: PLEX Giveaway Announcement",
author: "Wanderer Team",
cover_image_uri: "/images/news/2025/12-18-advent-giveaway/cover.jpg",
cover_image_uri: "/images/news/2025/12-18-advent-giveaway/cover.webp",
tags: ~w(event giveaway challenge christmas advent partnership),
description: "Join our Advent Christmas Giveaway Challenge! Win exclusive partnership codes every day for a week. Be the fastest to claim your reward!"
description: "Join our Advent Christmas Giveaway Challenge! Be the fastest to claim your reward!"
}
---
![Christmas Giveaway Challenge](/images/news/2025/12-18-advent-giveaway/cover.jpg "Christmas Giveaway Challenge")
### The Season of Giving
This holiday season, we're spreading some festive cheer with a special event for our community: the **Advent Christmas Giveaway Challenge**!
Starting next week, we'll be giving away **1 exclusive partnership code every day for 7 days**. But here's the twist — it's a challenge!
---
### How It Works
1. **Daily Giveaway:**
- Every day during the event week, a partnership code will be revealed at a specific scheduled time.
- The exact reveal time will be announced for each day.
2. **The Challenge:**
- When the code is revealed, it becomes visible to **all participants** at the exact same moment.
- **First person to activate the code wins!**
- Speed and timing are everything.
3. **One Code Per Day:**
- Each day features a single partnership code.
- Miss today? Come back tomorrow for another chance!
---
![Christmas Giveaway Challenge](/images/news/2025/12-18-advent-giveaway/cover.webp "Christmas Giveaway Challenge")
### Event Details
- **Event Name:** Advent Christmas Giveaway
- **Duration:** 1 week (7 days, 7 codes)
- **Organizer:** @Demiro (Wanderer core developer, EventCortex CTO)
- **Event Link:** [Advent Christmas Giveaway - EventCortex](https://eventcortex.com/events/invite/cYdBywu1ygfVS3UN6ZZcmDzL1q85aDmH)
- **Event Link:** [Advent Christmas Giveaway](https://eventcortex.com/events/invite/cYdBywu1ygfVS3UN6ZZcmDzL1q85aDmH)
### The Season of Giving
This holiday season, we're spreading some festive cheer with a special event for our community: the **Advent Christmas Giveaway Challenge**!
---
### Tips for Participants
- **Be Ready:** Know the reveal time and be online a few minutes early.
- **Stay Alert:** The code appears for everyone simultaneously — every second counts!
- **Keep Trying:** Didn't win today? There's always tomorrow's code.
---
### Why Participate?
### FINAL DAY
Partnership codes can be redeemed in EVE Online for **exclusive partnership SKINs** — unique ship skins that let you fly in style! This is your chance to grab one for free — if you're fast enough!
🎉 PLEX Giveaway Announcement! 🎉
Weve decided to give away 500 PLEX!
At each secret location, youll find 100 PLEX waiting for you (along with a skin 😉).
There will be a total of 5 secret locations —
see you on the spot! 🚀
Good luck, and may the fastest capsuleer win!

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

View File

@@ -49,6 +49,8 @@ defmodule WandererApp.Map.MapScopeFilteringTest do
setup do
# Setup system static info cache with both wormhole and k-space systems
setup_scope_test_systems()
# Setup known stargates between adjacent k-space systems
setup_kspace_stargates()
:ok
end
@@ -190,6 +192,30 @@ defmodule WandererApp.Map.MapScopeFilteringTest do
:ok
end
# Setup known stargates between adjacent k-space systems
# This ensures that k-space to k-space connections WITH stargates are properly filtered
# (connections WITHOUT stargates are treated as wormhole connections)
defp setup_kspace_stargates do
# Stargate between Halenan (HS) and Mili (HS) - adjacent high-sec systems
# Cache key format: "jump_#{smaller_id}_#{larger_id}"
halenan_mili_key = "jump_#{@hs_system_halenan}_#{@hs_system_mili}"
WandererApp.Cache.insert(halenan_mili_key, %{
from_solar_system_id: @hs_system_halenan,
to_solar_system_id: @hs_system_mili
})
# Stargate between Halenan (HS) and Halmah (LS) - adjacent high-sec to low-sec
halenan_halmah_key = "jump_#{@hs_system_halenan}_#{@ls_system_halmah}"
WandererApp.Cache.insert(halenan_halmah_key, %{
from_solar_system_id: @hs_system_halenan,
to_solar_system_id: @ls_system_halmah
})
:ok
end
describe "Scope filtering logic tests" do
# These tests verify the filtering logic without full integration
# The actual filtering is tested more comprehensively in map_scopes_test.exs

View File

@@ -0,0 +1,187 @@
defmodule WandererApp.Map.Server.AclScopesPropagationTest do
@moduledoc """
Unit tests for verifying that map scopes are properly propagated
when ACL updates occur.
This test verifies the fix in lib/wanderer_app/map/server/map_server_acls_impl.ex:59
where `scopes` was added to the map_update struct.
Bug: When users update map scope settings (Wormholes, High-Sec, Low-Sec, Null-Sec,
Pochven checkboxes), the map server's cached state wasn't being updated with the
new scopes array. This caused connection tracking to use stale scope settings
until the server was restarted.
Fix: Changed `map_update = %{acls: map.acls, scope: map.scope}`
To: `map_update = %{acls: map.acls, scope: map.scope, scopes: map.scopes}`
"""
use WandererApp.DataCase, async: false
import WandererAppWeb.Factory
describe "MapRepo.get returns scopes field" do
test "map scopes are loaded when fetching map data" do
# Create a user and character for map ownership
user = create_user()
character = create_character(%{user_id: user.id})
# Create a map with specific scopes
map =
create_map(%{
owner_id: character.id,
name: "Scopes Test",
slug: "scopes-prop-test-#{:rand.uniform(1_000_000)}",
scope: :wormholes,
scopes: [:wormholes, :hi, :low]
})
# Verify the map was created with the expected scopes
assert map.scopes == [:wormholes, :hi, :low]
# Fetch the map the same way AclsImpl.handle_map_acl_updated does
{:ok, fetched_map} =
WandererApp.MapRepo.get(map.id,
acls: [
:owner_id,
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
]
)
# Verify scopes are returned - this is what the fix relies on
assert fetched_map.scopes == [:wormholes, :hi, :low],
"MapRepo.get should return the scopes field. Got: #{inspect(fetched_map.scopes)}"
# Verify the scope (legacy) field is also present
assert fetched_map.scope == :wormholes
end
test "map scopes field is available for map_update construction" do
# Create test data
user = create_user()
character = create_character(%{user_id: user.id})
map =
create_map(%{
owner_id: character.id,
name: "Update Test",
slug: "scopes-update-test-#{:rand.uniform(1_000_000)}",
scope: :all,
scopes: [:wormholes, :hi, :low, :null, :pochven]
})
# Fetch map as AclsImpl does
{:ok, fetched_map} = WandererApp.MapRepo.get(map.id, acls: [:owner_id])
# Build map_update the same way the fixed code does
# This is the exact line that was fixed in map_server_acls_impl.ex:59
map_update = %{acls: fetched_map.acls, scope: fetched_map.scope, scopes: fetched_map.scopes}
# Verify all fields are present in the update struct
assert Map.has_key?(map_update, :acls), "map_update should include :acls"
assert Map.has_key?(map_update, :scope), "map_update should include :scope"
assert Map.has_key?(map_update, :scopes), "map_update should include :scopes"
# Verify the scopes value is correct
assert map_update.scopes == [:wormholes, :hi, :low, :null, :pochven],
"map_update.scopes should have the complete scopes array"
end
end
describe "scopes update in database" do
test "updating map scopes persists correctly" do
# Create test data
user = create_user()
character = create_character(%{user_id: user.id})
map =
create_map(%{
owner_id: character.id,
name: "DB Update Test",
slug: "scopes-db-test-#{:rand.uniform(1_000_000)}",
scope: :wormholes,
scopes: [:wormholes]
})
# Initial state
assert map.scopes == [:wormholes]
# Update scopes (simulating what the LiveView does)
{:ok, updated_map} =
WandererApp.Api.Map.update(map, %{
scopes: [:wormholes, :hi, :low, :null]
})
assert updated_map.scopes == [:wormholes, :hi, :low, :null],
"Database update should persist new scopes"
# Fetch again to confirm persistence
{:ok, refetched_map} = WandererApp.MapRepo.get(map.id, [])
assert refetched_map.scopes == [:wormholes, :hi, :low, :null],
"Refetched map should have updated scopes"
end
test "partial scopes update works correctly" do
# Create test data
user = create_user()
character = create_character(%{user_id: user.id})
map =
create_map(%{
owner_id: character.id,
name: "Partial Update",
slug: "partial-scopes-#{:rand.uniform(1_000_000)}",
scope: :wormholes,
scopes: [:wormholes, :hi, :low, :null, :pochven]
})
# Update to a subset of scopes
{:ok, updated_map} =
WandererApp.Api.Map.update(map, %{
scopes: [:wormholes, :null]
})
assert updated_map.scopes == [:wormholes, :null],
"Should be able to update to partial scopes"
end
end
describe "get_effective_scopes uses scopes array" do
alias WandererApp.Map.Server.CharactersImpl
test "get_effective_scopes returns scopes array when present" do
map_struct = %{scopes: [:wormholes, :hi, :low], scope: :all}
effective_scopes = CharactersImpl.get_effective_scopes(map_struct)
assert effective_scopes == [:wormholes, :hi, :low],
"get_effective_scopes should return scopes array when present"
end
test "get_effective_scopes falls back to legacy scope when scopes is empty" do
map_struct = %{scopes: [], scope: :wormholes}
effective_scopes = CharactersImpl.get_effective_scopes(map_struct)
assert effective_scopes == [:wormholes],
"get_effective_scopes should fall back to legacy scope conversion"
end
test "get_effective_scopes falls back to legacy scope when scopes is nil" do
map_struct = %{scopes: nil, scope: :all}
effective_scopes = CharactersImpl.get_effective_scopes(map_struct)
assert effective_scopes == [:wormholes, :hi, :low, :null, :pochven],
"get_effective_scopes should convert :all to full scope list"
end
test "get_effective_scopes defaults to [:wormholes] when no scope info" do
map_struct = %{}
effective_scopes = CharactersImpl.get_effective_scopes(map_struct)
assert effective_scopes == [:wormholes],
"get_effective_scopes should default to [:wormholes]"
end
end
end

View File

@@ -56,8 +56,12 @@ defmodule WandererApp.Map.Server.MapScopesTest do
30_000_101 => %{solar_system_id: 30_000_101, system_class: @ls},
# Nullsec system
30_000_200 => %{solar_system_id: 30_000_200, system_class: @ns},
# Another nullsec for tests
30_000_201 => %{solar_system_id: 30_000_201, system_class: @ns},
# Pochven system
30_000_300 => %{solar_system_id: 30_000_300, system_class: @pochven},
# Another pochven for tests
30_000_301 => %{solar_system_id: 30_000_301, system_class: @pochven},
# Jita (prohibited system - highsec)
30_000_142 => %{solar_system_id: 30_000_142, system_class: @hs}
}
@@ -244,18 +248,19 @@ defmodule WandererApp.Map.Server.MapScopesTest do
test "connection with multiple scopes" do
# With [:wormholes, :hi]:
# - WH to WH: valid (both match :wormholes)
# - HS to HS: valid (both match :hi)
# - HS to HS: valid (both match :hi, or wormhole if no stargate)
# - WH to HS: valid (wormhole border behavior - WH is wormhole, :wormholes enabled)
scopes = [:wormholes, :hi]
assert ConnectionsImpl.is_connection_valid(scopes, @wh_system_id, @c2_system_id) == true
assert ConnectionsImpl.is_connection_valid(scopes, @hs_system_id, 30_000_002) == true
assert ConnectionsImpl.is_connection_valid(scopes, @wh_system_id, @hs_system_id) == true
# LS to NS should not be valid with [:wormholes, :hi] (neither is WH, neither matches)
assert ConnectionsImpl.is_connection_valid(scopes, @ls_system_id, @ns_system_id) == false
# LS to NS with [:wormholes, :hi] - if no stargate exists, it's a wormhole connection
# With :wormholes enabled, wormhole connections are valid
assert ConnectionsImpl.is_connection_valid(scopes, @ls_system_id, @ns_system_id) == true
# HS to LS should not be valid with [:wormholes, :hi] (neither is WH, only HS matches)
assert ConnectionsImpl.is_connection_valid(scopes, @hs_system_id, @ls_system_id) == false
# HS to LS with [:wormholes, :hi] - if no stargate exists, it's a wormhole connection
assert ConnectionsImpl.is_connection_valid(scopes, @hs_system_id, @ls_system_id) == true
end
test "all scopes allows any connection" do
@@ -368,30 +373,32 @@ defmodule WandererApp.Map.Server.MapScopesTest do
true
end
test "K-SPACE ONLY: Hi-Sec->Hi-Sec with [:wormholes] is REJECTED" do
# No wormhole involved, neither matches :wormholes
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == false
test "K-SPACE ONLY: Hi-Sec->Hi-Sec with [:wormholes] is VALID when no stargate exists" do
# If no stargate exists between two k-space systems, it's a wormhole connection
# (The test systems don't have stargate data, so this is treated as a wormhole)
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == true
end
test "K-SPACE ONLY: Null->Hi-Sec with [:wormholes, :null] is REJECTED (no border for k-space)" do
# Neither system is a wormhole, so no border behavior
# Null matches :null, but Hi-Sec doesn't match any scope -> BOTH must match
test "K-SPACE ONLY: Null->Hi-Sec with [:wormholes, :null] is VALID when no stargate exists" do
# If no stargate exists, this is a wormhole connection through k-space
# With [:wormholes] enabled, wormhole connections are valid
assert ConnectionsImpl.is_connection_valid(
[:wormholes, :null],
@ns_system_id,
@hs_system_id
) ==
false
true
end
test "K-SPACE ONLY: Hi-Sec->Low-Sec with [:wormholes, :null] is REJECTED" do
# Neither Hi-Sec nor Low-Sec match [:wormholes, :null], no WH involved
test "K-SPACE ONLY: Hi-Sec->Low-Sec with [:wormholes, :null] is VALID when no stargate exists" do
# If no stargate exists, this is a wormhole connection
# With [:wormholes] enabled, wormhole connections are valid
assert ConnectionsImpl.is_connection_valid(
[:wormholes, :null],
@hs_system_id,
@ls_system_id
) ==
false
true
end
test "K-SPACE ONLY: Low-Sec->Hi-Sec with [:low] is REJECTED (no border for k-space)" do
@@ -437,29 +444,169 @@ defmodule WandererApp.Map.Server.MapScopesTest do
true
end
test "excluded path: k-space chain with [:wormholes] scope remains excluded" do
# If character moves within k-space (no WH involved), should be excluded
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == false
assert ConnectionsImpl.is_connection_valid([:wormholes], 30_000_002, @ls_system_id) == false
test "k-space chain with [:wormholes] scope is VALID when no stargates exist" do
# If no stargates exist between k-space systems, they're wormhole connections
# With [:wormholes] scope, these should be tracked
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002) == true
assert ConnectionsImpl.is_connection_valid([:wormholes], 30_000_002, @ls_system_id) == true
end
test "excluded path: Null->Hi-Sec->Low-Sec with [:wormholes, :null] - only Null tracked" do
# Character in Null (tracked) jumps to Hi-Sec (border - but NO wormhole!) -> REJECTED
# This is the key case: k-space to k-space should NOT add border systems
test "k-space chain with [:wormholes, :null] - wormhole connections are tracked" do
# If no stargates exist, these are wormhole connections through k-space
# With [:wormholes] enabled, all wormhole connections are tracked
assert ConnectionsImpl.is_connection_valid(
[:wormholes, :null],
@ns_system_id,
@hs_system_id
) ==
false
true
# Hi-Sec to Low-Sec also rejected (neither matches)
# Hi-Sec to Low-Sec is also a wormhole connection (no stargate in test data)
assert ConnectionsImpl.is_connection_valid(
[:wormholes, :null],
@hs_system_id,
@ls_system_id
) ==
false
true
end
end
describe "wormhole connections in k-space (unknown connections)" do
@moduledoc """
These tests verify the behavior for k-space to k-space connections that are
NOT known stargates. Such connections should be treated as wormhole connections.
Scenario: A player jumps from Low-Sec to Hi-Sec. If there's no stargate between
these systems, the jump must have been through a wormhole. With [:wormholes] scope,
this connection SHOULD be valid.
The connection TYPE (stargate vs wormhole) is determined separately in
maybe_add_connection using is_connection_valid(:stargates, ...).
"""
test "Low-Sec to Hi-Sec with [:wormholes] is valid when no stargate exists (wormhole connection)" do
# When there's no stargate between low-sec and hi-sec, the jump must be through a wormhole
# With [:wormholes] scope, this wormhole connection should be valid
#
# The test systems @ls_system_id and @hs_system_id don't have a known stargate between them
# (they're test systems not in the EVE jump database), so this should be treated as a wormhole
result = ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, @hs_system_id)
# Connection is valid because no stargate exists - it's a wormhole connection
assert result == true,
"K-space to K-space with [:wormholes] should be valid when no stargate exists"
end
test "Hi-Sec to Low-Sec with [:wormholes] is valid when no stargate exists" do
# Test the reverse direction
result = ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @ls_system_id)
assert result == true,
"Hi-Sec to Low-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Null-Sec to Hi-Sec with [:wormholes] is valid when no stargate exists" do
# Null to Hi-Sec through wormhole
result = ConnectionsImpl.is_connection_valid([:wormholes], @ns_system_id, @hs_system_id)
assert result == true,
"Null-Sec to Hi-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Low-Sec to Null-Sec with [:wormholes] is valid when no stargate exists" do
# Low to Null through wormhole
result = ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, @ns_system_id)
assert result == true,
"Low-Sec to Null-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Pochven to Hi-Sec with [:wormholes] is valid when no stargate exists" do
# Pochven has special wormhole connections to k-space
result = ConnectionsImpl.is_connection_valid([:wormholes], @pochven_id, @hs_system_id)
assert result == true,
"Pochven to Hi-Sec with [:wormholes] should be valid when no stargate exists"
end
# Same-space-type wormhole connections
# These verify that jumps within the same security class are valid when no stargate exists
test "Low-Sec to Low-Sec with [:wormholes] is valid when no stargate exists" do
# A wormhole can connect two low-sec systems
# With [:wormholes] scope and no known stargate, this should be tracked
result = ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, 30_000_101)
assert result == true,
"Low-Sec to Low-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Hi-Sec to Hi-Sec with [:wormholes] is valid when no stargate exists" do
# A wormhole can connect two hi-sec systems
# With [:wormholes] scope and no known stargate, this should be tracked
result = ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, 30_000_002)
assert result == true,
"Hi-Sec to Hi-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Null-Sec to Null-Sec with [:wormholes] is valid when no stargate exists" do
# A wormhole can connect two null-sec systems
# With [:wormholes] scope and no known stargate, this should be tracked
result = ConnectionsImpl.is_connection_valid([:wormholes], @ns_system_id, 30_000_201)
assert result == true,
"Null-Sec to Null-Sec with [:wormholes] should be valid when no stargate exists"
end
test "Pochven to Pochven with [:wormholes] is valid when no stargate exists" do
# A wormhole can connect two Pochven systems
# With [:wormholes] scope and no known stargate, this should be tracked
result = ConnectionsImpl.is_connection_valid([:wormholes], @pochven_id, 30_000_301)
assert result == true,
"Pochven to Pochven with [:wormholes] should be valid when no stargate exists"
end
# Cross-space-type comprehensive tests
# Verify all k-space combinations work correctly
test "all k-space combinations with [:wormholes] are valid when no stargate exists" do
# Test all combinations of k-space security types
# All should be valid because no stargates exist in test data = wormhole connections
# Hi-Sec combinations
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @ls_system_id) == true,
"Hi->Low should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @ns_system_id) == true,
"Hi->Null should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @hs_system_id, @pochven_id) == true,
"Hi->Pochven should be valid"
# Low-Sec combinations
assert ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, @hs_system_id) == true,
"Low->Hi should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, @ns_system_id) == true,
"Low->Null should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @ls_system_id, @pochven_id) == true,
"Low->Pochven should be valid"
# Null-Sec combinations
assert ConnectionsImpl.is_connection_valid([:wormholes], @ns_system_id, @hs_system_id) == true,
"Null->Hi should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @ns_system_id, @ls_system_id) == true,
"Null->Low should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @ns_system_id, @pochven_id) == true,
"Null->Pochven should be valid"
# Pochven combinations
assert ConnectionsImpl.is_connection_valid([:wormholes], @pochven_id, @hs_system_id) == true,
"Pochven->Hi should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @pochven_id, @ls_system_id) == true,
"Pochven->Low should be valid"
assert ConnectionsImpl.is_connection_valid([:wormholes], @pochven_id, @ns_system_id) == true,
"Pochven->Null should be valid"
end
end
end