11 changed files with 403 additions and 42 deletions
@ -0,0 +1,137 @@ |
|||||||
|
defmodule GcIndexRelay.Nostr.ValidatorTest do |
||||||
|
use ExUnit.Case, async: true |
||||||
|
|
||||||
|
alias GcIndexRelay.Nostr.Validator |
||||||
|
alias GcIndexRelay.Nostr.PubEvent |
||||||
|
|
||||||
|
import GcIndexRelay.NostrFixtures |
||||||
|
|
||||||
|
@moduletag :unit |
||||||
|
|
||||||
|
describe "validate_id/1" do |
||||||
|
test "returns {:ok, event} for valid event ID" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
|
||||||
|
assert {:ok, ^event} = Validator.validate_id(event) |
||||||
|
end |
||||||
|
|
||||||
|
test "returns {:error, message} for invalid event ID" do |
||||||
|
event = invalid_id_pub_event_fixture() |
||||||
|
|
||||||
|
assert {:error, message} = Validator.validate_id(event) |
||||||
|
assert message =~ "ID" |
||||||
|
assert message =~ "is invalid" |
||||||
|
end |
||||||
|
|
||||||
|
test "handles nil id gracefully" do |
||||||
|
event = %PubEvent{ |
||||||
|
id: nil, |
||||||
|
pubkey: "0db15182c4ad3418b4fbab75304be7ade9cfa430a21c1c5320c9298f54ea5406", |
||||||
|
created_at: 1_640_000_000, |
||||||
|
kind: 1, |
||||||
|
tags: [], |
||||||
|
content: "Test content", |
||||||
|
sig: |
||||||
|
"304402201a9c5a7c3f5b2e4d6e8a9f0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e02204f5e6d7c8b9a0f1e2d3c4b5a6978695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9" |
||||||
|
} |
||||||
|
|
||||||
|
# Should return error for nil id |
||||||
|
assert {:error, _message} = Validator.validate_id(event) |
||||||
|
end |
||||||
|
|
||||||
|
test "handles non-hex characters in id" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
|
||||||
|
invalid_event = %{ |
||||||
|
event |
||||||
|
| id: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" |
||||||
|
} |
||||||
|
|
||||||
|
assert {:error, _message} = Validator.validate_id(invalid_event) |
||||||
|
end |
||||||
|
|
||||||
|
test "handles incorrect length id" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
# ID should be 64 hex chars (32 bytes), use 32 chars instead |
||||||
|
short_id = String.duplicate("a", 32) |
||||||
|
invalid_event = %{event | id: short_id} |
||||||
|
|
||||||
|
assert {:error, _message} = Validator.validate_id(invalid_event) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "validate_signature/1" do |
||||||
|
test "returns {:ok, event} for valid signature" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
|
||||||
|
assert {:ok, ^event} = Validator.validate_signature(event) |
||||||
|
end |
||||||
|
|
||||||
|
test "returns {:error, message} for invalid signature" do |
||||||
|
event = invalid_sig_pub_event_fixture() |
||||||
|
|
||||||
|
assert {:error, message} = Validator.validate_signature(event) |
||||||
|
assert message =~ "Signature" |
||||||
|
assert message =~ "is invalid" |
||||||
|
end |
||||||
|
|
||||||
|
test "returns {:error, message} for mismatched pubkey" do |
||||||
|
keypairs = test_keypairs() |
||||||
|
|
||||||
|
# Create event signed by keypair1 |
||||||
|
event = valid_pub_event_fixture(keypair: :keypair1) |
||||||
|
|
||||||
|
# Replace pubkey with keypair2's pubkey (signature won't match) |
||||||
|
mismatched_event = %{event | pubkey: keypairs.keypair2.public_key_hex} |
||||||
|
|
||||||
|
assert {:error, message} = Validator.validate_signature(mismatched_event) |
||||||
|
assert message =~ "Signature" |
||||||
|
assert message =~ "is invalid" |
||||||
|
end |
||||||
|
|
||||||
|
test "handles nil signature gracefully" do |
||||||
|
event = %PubEvent{ |
||||||
|
id: "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed6a65", |
||||||
|
pubkey: "0db15182c4ad3418b4fbab75304be7ade9cfa430a21c1c5320c9298f54ea5406", |
||||||
|
created_at: 1_640_000_000, |
||||||
|
kind: 1, |
||||||
|
tags: [], |
||||||
|
content: "Test content", |
||||||
|
sig: nil |
||||||
|
} |
||||||
|
|
||||||
|
# Should return error |
||||||
|
assert {:error, _message} = Validator.validate_signature(event) |
||||||
|
end |
||||||
|
|
||||||
|
test "handles non-hex characters in signature" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
|
||||||
|
invalid_event = %{ |
||||||
|
event |
||||||
|
| sig: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" |
||||||
|
} |
||||||
|
|
||||||
|
assert {:error, _message} = Validator.validate_signature(invalid_event) |
||||||
|
end |
||||||
|
|
||||||
|
test "handles incorrect length signature" do |
||||||
|
event = valid_pub_event_fixture() |
||||||
|
# Nostr event signatures must be 64 bytes |
||||||
|
short_sig = String.duplicate("a", 32) |
||||||
|
invalid_event = %{event | sig: short_sig} |
||||||
|
|
||||||
|
assert {:error, _message} = Validator.validate_signature(invalid_event) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "static reference test" do |
||||||
|
test "validates against known-good pre-computed event" do |
||||||
|
event = static_valid_pub_event() |
||||||
|
|
||||||
|
# Both ID and signature should validate |
||||||
|
assert {:ok, ^event} = Validator.validate_id(event) |
||||||
|
assert {:ok, ^event} = Validator.validate_signature(event) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
@ -1,19 +1,11 @@ |
|||||||
defmodule GcIndexRelay.NostrTest do |
defmodule GcIndexRelay.NostrTest do |
||||||
use GcIndexRelay.DataCase |
use GcIndexRelay.DataCase |
||||||
|
|
||||||
alias GcIndexRelay.Nostr |
|
||||||
|
|
||||||
describe "events" do |
describe "events" do |
||||||
alias GcIndexRelay.Nostr.Event |
# Tests to be added |
||||||
|
|
||||||
import GcIndexRelay.NostrFixtures |
|
||||||
|
|
||||||
@invalid_attrs %{name: nil} |
|
||||||
end |
end |
||||||
|
|
||||||
describe "tags" do |
describe "tags" do |
||||||
alias GcIndexRelay.Nostr.Tag |
# Tests to be added |
||||||
|
|
||||||
import GcIndexRelay.NostrFixtures |
|
||||||
end |
end |
||||||
end |
end |
||||||
|
|||||||
@ -1,2 +1,7 @@ |
|||||||
ExUnit.start() |
ExUnit.start() |
||||||
Ecto.Adapters.SQL.Sandbox.mode(GcIndexRelay.Repo, :manual) |
|
||||||
|
# Only set up the database sandbox if the Repo was started |
||||||
|
# This allows unit tests to run without a database connection |
||||||
|
if Application.get_env(:gc_index_relay, :start_repo, true) do |
||||||
|
Ecto.Adapters.SQL.Sandbox.mode(GcIndexRelay.Repo, :manual) |
||||||
|
end |
||||||
|
|||||||
Loading…
Reference in new issue