package service import ( "context" "errors" "testing" ) type fakeCardToIBANClient struct { result ConversionResult err error called bool receivedCard string receivedContext context.Context } func (f *fakeCardToIBANClient) Convert( ctx context.Context, cardNumber string, ) (ConversionResult, error) { f.called = true f.receivedCard = cardNumber f.receivedContext = ctx return f.result, f.err } func TestCardServiceConvertCardToIBANSuccess(t *testing.T) { client := &fakeCardToIBANClient{ result: ConversionResult{ IBAN: "IR123456789012345678901234", UpstreamHTTPStatus: 200, RawResponse: []byte(`{"success":true}`), }, } service := NewCardService(client) cardNumber := "6037991234567890" result, err := service.ConvertCardToIBAN( context.Background(), cardNumber, ) if err != nil { t.Fatalf("ConvertCardToIBAN() unexpected error: %v", err) } if result.IBAN != client.result.IBAN { t.Errorf( "ConvertCardToIBAN() iban = %q, want %q", result.IBAN, client.result.IBAN, ) } if result.UpstreamHTTPStatus != client.result.UpstreamHTTPStatus { t.Errorf( "ConvertCardToIBAN() status = %d, want %d", result.UpstreamHTTPStatus, client.result.UpstreamHTTPStatus, ) } if !client.called { t.Error("expected client to be called") } if client.receivedCard != cardNumber { t.Errorf( "client received card = %q, want %q", client.receivedCard, cardNumber, ) } } func TestCardServiceRejectsInvalidCardBeforeClientCall(t *testing.T) { client := &fakeCardToIBANClient{} service := NewCardService(client) _, err := service.ConvertCardToIBAN( context.Background(), "123", ) if err == nil { t.Fatal("expected validation error") } if client.called { t.Error("client should not be called for an invalid card") } } func TestCardServiceReturnsClientError(t *testing.T) { clientErr := errors.New("upstream unavailable") client := &fakeCardToIBANClient{ result: ConversionResult{ UpstreamHTTPStatus: 503, RawResponse: []byte(`{"error":"unavailable"}`), }, err: clientErr, } service := NewCardService(client) result, err := service.ConvertCardToIBAN( context.Background(), "6037991234567890", ) if err == nil { t.Fatal("expected client error") } if !errors.Is(err, clientErr) { t.Errorf( "ConvertCardToIBAN() error = %v, want wrapped %v", err, clientErr, ) } if result.UpstreamHTTPStatus != 503 { t.Errorf( "ConvertCardToIBAN() status = %d, want 503", result.UpstreamHTTPStatus, ) } } func TestCardServicePassesContextToClient(t *testing.T) { client := &fakeCardToIBANClient{ result: ConversionResult{ IBAN: "IR123456789012345678901234", }, } service := NewCardService(client) ctx, cancel := context.WithCancel(context.Background()) defer cancel() _, err := service.ConvertCardToIBAN( ctx, "6037991234567890", ) if err != nil { t.Fatalf("ConvertCardToIBAN() unexpected error: %v", err) } if client.receivedContext != ctx { t.Error("service did not pass the request context to the client") } }