// Copyright (c) 2017-2026 Lethean (https://lt.hn) // SPDX-License-Identifier: EUPL-1.2 package node import ( "net/http" "net/http/httptest" "testing" ) func TestParseComment_Good(t *testing.T) { tests := []struct { input string key string want string }{ {"v=lthn1;type=gateway;cap=vpn,dns", "type", "gateway"}, {"v=lthn1;cap=pool", "cap", "pool"}, {"v=lthn1", "v", "lthn1"}, } for _, testCase := range tests { result := parseComment(testCase.input) if result[testCase.key] != testCase.want { t.Errorf("parseComment(%q)[%q] = %q, want %q", testCase.input, testCase.key, result[testCase.key], testCase.want) } } } func TestParseComment_Bad(t *testing.T) { tests := []struct { input string key string want string }{ {"noequals", "noequals", ""}, {"k=v", "missing", ""}, {"=v", "", ""}, } for _, testCase := range tests { result := parseComment(testCase.input) if result[testCase.key] != testCase.want { t.Errorf("parseComment(%q)[%q] = %q, want %q", testCase.input, testCase.key, result[testCase.key], testCase.want) } } } func TestParseComment_Ugly(t *testing.T) { tests := []struct { name string input string key string want string }{ {"empty string", "", "k", ""}, {"semicolons only", ";;;", "k", ""}, {"duplicate keys last wins", "k=first;k=second", "k", "second"}, {"value with equals", "k=v=extra", "k", "v=extra"}, } for _, testCase := range tests { result := parseComment(testCase.input) if result[testCase.key] != testCase.want { t.Errorf("%s: parseComment(%q)[%q] = %q, want %q", testCase.name, testCase.input, testCase.key, result[testCase.key], testCase.want) } } } func TestGetChainInfo_Good(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"result":{"height":6292,"alias_count":5,"tx_pool_size":0,"difficulty":12345}}`)) })) defer server.Close() info, err := GetChainInfo(server.URL) if err != nil { t.Fatalf("GetChainInfo returned unexpected error: %v", err) } if info.Height != 6292 { t.Errorf("expected height 6292, got %d", info.Height) } if !info.Synced { t.Error("expected Synced=true when height > 0") } if info.AliasCount != 5 { t.Errorf("expected alias_count 5, got %d", info.AliasCount) } } func TestGetChainInfo_Bad(t *testing.T) { _, err := GetChainInfo("http://127.0.0.1:19999") if err == nil { t.Error("expected error for unreachable daemon") } } func TestGetChainInfo_Ugly(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`not-valid-json`)) })) defer server.Close() _, err := GetChainInfo(server.URL) if err == nil { t.Error("expected error when daemon returns malformed JSON") } } func TestDiscoverPools_Good(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"result":{"aliases":[{"alias":"pool.lthn","address":"LTHNabc","comment":"v=lthn1;type=pool;cap=pool"}]}}`)) })) defer server.Close() pools := DiscoverPools(server.URL) if len(pools) != 1 { t.Fatalf("expected 1 pool, got %d", len(pools)) } if pools[0].Name != "pool.lthn" { t.Errorf("expected pool name 'pool.lthn', got '%s'", pools[0].Name) } } func TestDiscoverPools_Bad(t *testing.T) { pools := DiscoverPools("http://127.0.0.1:19999") if len(pools) != 0 { t.Errorf("expected 0 pools for unreachable daemon, got %d", len(pools)) } } func TestDiscoverPools_Ugly(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"result":{"aliases":[{"alias":"gw.lthn","address":"LTHNxyz","comment":"v=lthn1;type=gateway;cap=vpn"}]}}`)) })) defer server.Close() pools := DiscoverPools(server.URL) if len(pools) != 0 { t.Errorf("expected 0 pools when no alias comment contains 'pool', got %d", len(pools)) } } func TestDiscoverGateways_Good(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"result":{"aliases":[{"alias":"gw.lthn","address":"LTHNxyz","comment":"v=lthn1;type=gateway;cap=vpn,dns"}]}}`)) })) defer server.Close() gateways := DiscoverGateways(server.URL) if len(gateways) != 1 { t.Fatalf("expected 1 gateway, got %d", len(gateways)) } if gateways[0].Name != "gw.lthn" { t.Errorf("expected gateway name 'gw.lthn', got '%s'", gateways[0].Name) } } func TestDiscoverGateways_Bad(t *testing.T) { gateways := DiscoverGateways("http://127.0.0.1:19999") if len(gateways) != 0 { t.Errorf("expected 0 gateways for unreachable daemon, got %d", len(gateways)) } } func TestDiscoverGateways_Ugly(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"result":{"aliases":[{"alias":"pool.lthn","address":"LTHNabc","comment":"v=lthn1;type=pool;cap=pool"}]}}`)) })) defer server.Close() gateways := DiscoverGateways(server.URL) if len(gateways) != 0 { t.Errorf("expected 0 gateways when no alias comment contains 'type=gateway', got %d", len(gateways)) } }