/* * NIP-21 URI Scheme Test Suite * Tests nostr: URI parsing and construction functionality * Following TESTS POLICY: Shows expected vs actual values */ #define _GNU_SOURCE // For strdup on Linux #include #include #include #include #include "../nostr_core/nip021.h" #include "../nostr_core/nostr_common.h" #include "../nostr_core/utils.h" // Ensure strdup is declared #ifndef strdup extern char *strdup(const char *s); #endif // Test counter for tracking progress static int test_count = 0; static int passed_tests = 0; void print_test_header(const char* test_name) { test_count++; printf("\n=== TEST %d: %s ===\n", test_count, test_name); } void print_test_result(int passed, const char* test_name) { if (passed) { passed_tests++; printf("✅ PASS: %s\n", test_name); } else { printf("❌ FAIL: %s\n", test_name); } } // Test 1: Parse note URI int test_parse_note_uri(void) { print_test_header("Parse note: URI"); // First build a valid note URI, then parse it unsigned char event_id[32]; nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32); char built_uri[200]; int build_result = nostr_build_uri_note(event_id, built_uri, sizeof(built_uri)); if (build_result != NOSTR_SUCCESS) { printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result)); return 0; } printf("Input URI: %s\n", built_uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(built_uri, &result); printf("Expected: NOSTR_SUCCESS (0)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); if (parse_result != NOSTR_SUCCESS) { return 0; } printf("Expected type: NOSTR_URI_NOTE\n"); printf("Actual type: %d\n", result.type); if (result.type != NOSTR_URI_NOTE) { return 0; } printf("Expected event ID to be set\n"); printf("Event ID present: %s\n", result.data.event_id[0] ? "yes" : "no"); // Verify the parsed event ID matches the original int event_id_match = (memcmp(result.data.event_id, event_id, 32) == 0); printf("Event ID matches original: %s\n", event_id_match ? "yes" : "no"); return (result.type == NOSTR_URI_NOTE && event_id_match); } // Test 2: Parse nprofile URI int test_parse_nprofile_uri(void) { print_test_header("Parse nprofile: URI"); // First build a valid nprofile URI, then parse it unsigned char pubkey[32]; nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32); const char* relays[] = {"wss://relay.example.com"}; char built_uri[300]; int build_result = nostr_build_uri_nprofile(pubkey, relays, 1, built_uri, sizeof(built_uri)); if (build_result != NOSTR_SUCCESS) { printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result)); return 0; } printf("Input URI: %s\n", built_uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(built_uri, &result); printf("Expected: NOSTR_SUCCESS (0)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); if (parse_result != NOSTR_SUCCESS) { return 0; } printf("Expected type: NOSTR_URI_NPROFILE\n"); printf("Actual type: %d\n", result.type); if (result.type != NOSTR_URI_NPROFILE) { return 0; } // Verify the parsed pubkey matches the original int pubkey_match = (memcmp(result.data.nprofile.pubkey, pubkey, 32) == 0); printf("Pubkey matches original: %s\n", pubkey_match ? "yes" : "no"); // Verify relay count printf("Expected relay count: 1\n"); printf("Actual relay count: %d\n", result.data.nprofile.relay_count); return (result.type == NOSTR_URI_NPROFILE && pubkey_match && result.data.nprofile.relay_count == 1); } // Test 3: Parse nevent URI int test_parse_nevent_uri(void) { print_test_header("Parse nevent: URI"); // First build a valid nevent URI, then parse it unsigned char event_id[32]; nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32); const char* relays[] = {"wss://relay.example.com"}; char built_uri[400]; int build_result = nostr_build_uri_nevent(event_id, relays, 1, NULL, 1, 1234567890, built_uri, sizeof(built_uri)); if (build_result != NOSTR_SUCCESS) { printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result)); return 0; } printf("Input URI: %s\n", built_uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(built_uri, &result); printf("Expected: NOSTR_SUCCESS (0)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); if (parse_result != NOSTR_SUCCESS) { return 0; } printf("Expected type: NOSTR_URI_NEVENT\n"); printf("Actual type: %d\n", result.type); if (result.type != NOSTR_URI_NEVENT) { return 0; } // Verify the parsed event ID matches the original int event_id_match = (memcmp(result.data.nevent.event_id, event_id, 32) == 0); printf("Event ID matches original: %s\n", event_id_match ? "yes" : "no"); // Verify kind printf("Expected kind: 1\n"); printf("Actual kind: %d\n", result.data.nevent.kind ? *result.data.nevent.kind : -1); // Verify relay count printf("Expected relay count: 1\n"); printf("Actual relay count: %d\n", result.data.nevent.relay_count); return (result.type == NOSTR_URI_NEVENT && event_id_match && result.data.nevent.relay_count == 1); } // Test 4: Parse naddr URI int test_parse_naddr_uri(void) { print_test_header("Parse naddr: URI"); // First build a valid naddr URI, then parse it const char* identifier = "draft"; unsigned char pubkey[32]; nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32); const char* relays[] = {"wss://relay.example.com"}; char built_uri[400]; int build_result = nostr_build_uri_naddr(identifier, pubkey, 30023, relays, 1, built_uri, sizeof(built_uri)); if (build_result != NOSTR_SUCCESS) { printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result)); return 0; } printf("Input URI: %s\n", built_uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(built_uri, &result); printf("Expected: NOSTR_SUCCESS (0)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); if (parse_result != NOSTR_SUCCESS) { return 0; } printf("Expected type: NOSTR_URI_NADDR\n"); printf("Actual type: %d\n", result.type); if (result.type != NOSTR_URI_NADDR) { return 0; } // Verify the parsed identifier matches the original int identifier_match = (strcmp(result.data.naddr.identifier, identifier) == 0); printf("Identifier matches original: %s\n", identifier_match ? "yes" : "no"); // Verify kind printf("Expected kind: 30023\n"); printf("Actual kind: %d\n", result.data.naddr.kind); // Verify relay count printf("Expected relay count: 1\n"); printf("Actual relay count: %d\n", result.data.naddr.relay_count); return (result.type == NOSTR_URI_NADDR && identifier_match && result.data.naddr.relay_count == 1); } // Test 5: Invalid URI (wrong prefix) int test_invalid_uri_prefix(void) { print_test_header("Invalid URI - Wrong Prefix"); const char* uri = "bitcoin:note1example"; printf("Input URI: %s\n", uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(uri, &result); printf("Expected: NOSTR_ERROR_INVALID_INPUT (-1)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); return (parse_result == NOSTR_ERROR_INVALID_INPUT); } // Test 6: Invalid URI (missing colon) int test_invalid_uri_no_colon(void) { print_test_header("Invalid URI - No Colon"); const char* uri = "nostrnote1example"; printf("Input URI: %s\n", uri); nostr_uri_result_t result; int parse_result = nostr_parse_uri(uri, &result); printf("Expected: NOSTR_ERROR_INVALID_INPUT (-1)\n"); printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result)); return (parse_result == NOSTR_ERROR_INVALID_INPUT); } // Test 7: Build note URI int test_build_note_uri(void) { print_test_header("Build note: URI"); unsigned char event_id[32]; nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32); printf("Input event ID: f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0\n"); char uri[200]; int result = nostr_build_uri_note(event_id, uri, sizeof(uri)); printf("Build result: %d (%s)\n", result, nostr_strerror(result)); if (result != NOSTR_SUCCESS) { return 0; } printf("Built URI: %s\n", uri); int success = (strncmp(uri, "nostr:note1", 11) == 0); printf("Expected: URI starts with 'nostr:note1'\n"); printf("Actual: %s\n", success ? "yes" : "no"); return success; } // Test 8: Build nprofile URI int test_build_nprofile_uri(void) { print_test_header("Build nprofile: URI"); unsigned char pubkey[32]; nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32); const char* relays[] = {"wss://relay.example.com", "wss://relay2.example.com"}; printf("Input pubkey: aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4\n"); char uri[300]; int result = nostr_build_uri_nprofile(pubkey, relays, 2, uri, sizeof(uri)); printf("Build result: %d (%s)\n", result, nostr_strerror(result)); if (result != NOSTR_SUCCESS) { return 0; } printf("Built URI: %s\n", uri); int success = (strncmp(uri, "nostr:nprofile1", 14) == 0); printf("Expected: URI starts with 'nostr:nprofile1'\n"); printf("Actual: %s\n", success ? "yes" : "no"); return success; } int main(void) { printf("=== NIP-21 URI Scheme Test Suite ===\n"); printf("Following TESTS POLICY: Shows expected vs actual values\n"); // Initialize crypto library if (nostr_init() != NOSTR_SUCCESS) { printf("❌ Failed to initialize nostr library\n"); return 1; } int all_passed = 1; int test_result; // Valid URI parsing tests test_result = test_parse_note_uri(); print_test_result(test_result, "Parse note: URI"); if (!test_result) all_passed = 0; test_result = test_parse_nprofile_uri(); print_test_result(test_result, "Parse nprofile: URI"); if (!test_result) all_passed = 0; test_result = test_parse_nevent_uri(); print_test_result(test_result, "Parse nevent: URI"); if (!test_result) all_passed = 0; test_result = test_parse_naddr_uri(); print_test_result(test_result, "Parse naddr: URI"); if (!test_result) all_passed = 0; // Invalid URI tests test_result = test_invalid_uri_prefix(); print_test_result(test_result, "Invalid URI - Wrong Prefix"); if (!test_result) all_passed = 0; test_result = test_invalid_uri_no_colon(); print_test_result(test_result, "Invalid URI - No Colon"); if (!test_result) all_passed = 0; // URI building tests test_result = test_build_note_uri(); print_test_result(test_result, "Build note: URI"); if (!test_result) all_passed = 0; test_result = test_build_nprofile_uri(); print_test_result(test_result, "Build nprofile: URI"); if (!test_result) all_passed = 0; // Summary printf("\n=== TEST SUMMARY ===\n"); printf("Total tests: %d\n", test_count); printf("Passed: %d\n", passed_tests); printf("Failed: %d\n", test_count - passed_tests); if (all_passed) { printf("🎉 ALL TESTS PASSED! NIP-21 URI scheme implementation is working correctly.\n"); } else { printf("❌ SOME TESTS FAILED. Please review the output above.\n"); } nostr_cleanup(); return all_passed ? 0 : 1; }