11 changed files with 403 additions and 42 deletions
@ -0,0 +1,137 @@
@@ -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 @@
@@ -1,19 +1,11 @@
|
||||
defmodule GcIndexRelay.NostrTest do |
||||
use GcIndexRelay.DataCase |
||||
|
||||
alias GcIndexRelay.Nostr |
||||
|
||||
describe "events" do |
||||
alias GcIndexRelay.Nostr.Event |
||||
|
||||
import GcIndexRelay.NostrFixtures |
||||
|
||||
@invalid_attrs %{name: nil} |
||||
# Tests to be added |
||||
end |
||||
|
||||
describe "tags" do |
||||
alias GcIndexRelay.Nostr.Tag |
||||
|
||||
import GcIndexRelay.NostrFixtures |
||||
# Tests to be added |
||||
end |
||||
end |
||||
|
||||
@ -1,2 +1,7 @@
@@ -1,2 +1,7 @@
|
||||
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