Files
2026-06-06 22:33:15 +02:00

163 lines
9.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Linq;
using AwesomeAssertions;
using NUnit.Framework;
using Soneta.Business;
using Soneta.Handel;
using Soneta.Types;
namespace Soneta.Skills.Test.Handel.DokumentyHandlowe;
/// <summary>
/// Rozdział 7 — Cechy (Features) na dokumencie handlowym (wzorce W40W42).
/// <para>
/// Cechy (<see cref="FeatureCollection"/>) to definiowalne informacje przypisane do <c>Row</c> —
/// tu: do dokumentu (<see cref="DokumentHandlowy"/>) i pozycji (<see cref="PozycjaDokHandlowego"/>).
/// Cecha jest adresowana <b>po nazwie definicji</b> (<c>FeatureDefinition</c>), a samo jej istnienie
/// zależy od konfiguracji wdrożenia — nie jest gwarantowane w bazie Demo.
/// </para>
/// <para>
/// Z tego powodu testy w tym rozdziale celują w <b>bezpieczną ścieżkę</b>: dostępność kolekcji
/// <c>Features</c>. Jednocześnie dokumentują <b>kontraktowe rzucanie wyjątku</b> przy odwołaniu do
/// cechy bez <c>FeatureSetDefinition</c>: zarówno <c>Features.Exists(nazwa)</c>, jak i warunek
/// serwerowy po string-path <c>"Features.Nazwa"</c> (<c>FieldCondition</c>) dla NIEZDEFINIOWANEJ
/// cechy rzucają <see cref="System.ArgumentException"/> — NIE zwracają false ani pustego zbioru.
/// Testy zapisu wartości cech (W41) oraz filtrowania zwracającego rekordy (W42) są <b>pominięte</b>,
/// bo wymagałyby wcześniej utworzonej definicji cechy, której Demo nie gwarantuje.
/// </para>
/// </summary>
[TestFixture]
public class Rozdzial07_CechyTest : DokumentHandlowyTestBase
{
// Nazwa cechy gwarantowanie niezdefiniowana w Demo — używana do testów bezpiecznej ścieżki.
// (Losowy, mało prawdopodobny identyfikator, by uniknąć kolizji z realną definicją wdrożenia.)
private const string NieistniejacaCecha = "SkillTestCechaXyz";
// ---------------------------------------------------------------------------------------------
// W41 — Odczyt i zapis cech (Features)
// ---------------------------------------------------------------------------------------------
[Test]
[Description("W41: property Features dokumentu jest dostępna (nie-null) zaraz po utworzeniu dokumentu.")]
public void Features_NaDokumencie_JestDostepna()
{
// Tworzymy minimalny dokument przychodowy (PW) na magazynie Firma — bez kontrahenta.
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Kolekcja Features istnieje zawsze, niezależnie od tego, czy zdefiniowano jakiekolwiek cechy.
dok.Features.Should().NotBeNull();
// Definicje cech to obiekt FeatureDefinitions (może być pusty, ale dostępny).
dok.Features.Definitions.Should().NotBeNull();
// Features.Row wskazuje z powrotem na dokument-właściciela.
dok.Features.Row.Should().BeSameAs(dok);
}
[Test]
[Description("W41: property Features pozycji dokumentu jest dostępna (nie-null) po dodaniu pozycji.")]
public void Features_NaPozycji_JestDostepna()
{
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Pozycję dodajemy w transakcji edycyjnej (każde tworzenie/edycja Row tego wymaga).
PozycjaDokHandlowego poz = null;
InTransaction(() => poz = DodajPozycje(dok, Towar(Towar_.Bikini), ilosc: 1, cena: 5));
// Kolekcja Features pozycji jest dostępna analogicznie do dokumentu.
poz.Features.Should().NotBeNull();
poz.Features.Row.Should().BeSameAs(poz);
}
[Test]
[Description("W41: Features.Exists(nazwa) dla NIEZDEFINIOWANEJ cechy RZUCA ArgumentException " +
"(odwołanie do cechy bez FeatureSetDefinition nie jest bezpieczne — nie zwraca false).")]
public void Features_Exists_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Kolekcja Features jest dostępna zawsze — niezależnie od konfiguracji cech.
dok.Features.Should().NotBeNull();
// UWAGA: Exists NIE jest bezpiecznym sprawdzeniem istnienia dla cechy, której nikt nie
// zdefiniował (brak FeatureSetDefinition). Odwołanie do takiej cechy rzuca ArgumentException
// ("nie znaleziono definicji cechy") — Exists NIE zwraca false dla nieznanej cechy.
Assert.Throws<System.ArgumentException>(() => dok.Features.Exists(NieistniejacaCecha));
}
// --- POMINIĘTE (W41 zapis): ustawienie wartości cechy ---
// Powód: zapis dok["Nazwa"] = wartość wymaga istniejącej definicji cechy (FeatureDefinition)
// zarejestrowanej dla tabeli DokHandlowe / PozycjeDokHan. Baza Demo nie gwarantuje żadnej
// takiej definicji, a tworzenie nowych definicji cech wykracza poza zakres tego rozdziału
// (i poza bezpieczną ścieżkę dla dodatku zewnętrznego). Odwołanie do niezdefiniowanej cechy
// rzuciłoby wyjątek, więc testu zapisu świadomie NIE piszemy.
// ---------------------------------------------------------------------------------------------
// W42 — Filtrowanie / wyszukiwanie po wartości cechy (serwerowo)
// ---------------------------------------------------------------------------------------------
[Test]
[Description("W42: warunek serwerowy FieldCondition.Equal po string-path 'Features.Nazwa' " +
"dla NIEZDEFINIOWANEJ cechy RZUCA ArgumentException przy aplikacji na indeksie dokumentów.")]
public void FiltrPoCesze_NaIndeksieDokumentow_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
// Cechy adresuje się STRING-PATHEM "Features.Nazwa" — Features.X nie jest typowaną property
// Row, więc nie da się jej użyć w wyrażeniu LINQ. Warunek budujemy jako FieldCondition.
var warunek = new FieldCondition.Equal($"Features.{NieistniejacaCecha}", "dowolna");
// Filtr serwerowy po cesze BEZ FeatureSetDefinition nie zwraca pustego zbioru — rzuca
// ArgumentException ("nie znaleziono definicji cechy") już przy budowaniu/aplikacji zapytania.
// Demo nie gwarantuje żadnej zdefiniowanej cechy, więc to zachowanie jest deterministyczne.
Assert.Throws<System.ArgumentException>(() =>
Handel.DokHandlowe.WgDaty[warunek].Cast<DokumentHandlowy>().ToArray());
}
[Test]
[Description("W42: złożony warunek RowCondition.And/FieldCondition po NIEZDEFINIOWANEJ cesze " +
"RZUCA ArgumentException przy wykonaniu serwerowym (brak FeatureSetDefinition).")]
public void FiltrPoCesze_WarunekZlozony_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
// Składanie warunków serwerowych: cecha-bool ORAZ cecha-data >= dziś.
// Wartości podajemy w typie zgodnym z typem cechy (bool dla Bool, Date dla Date) — zgodnie
// z W42. Sam warunek się składa, ale wykonanie na indeksie wymaga definicji cechy.
var warunek = new RowCondition.And(
new FieldCondition.Equal($"Features.{NieistniejacaCecha}", true),
new FieldCondition.GreaterEqual($"Features.{NieistniejacaCecha}Data", Date.Today));
// Brak FeatureSetDefinition dla cechy → ArgumentException przy aplikacji warunku na indeksie
// (nie pusty zbiór). Deterministyczne w Demo, które nie gwarantuje żadnej zdefiniowanej cechy.
Assert.Throws<System.ArgumentException>(() =>
Handel.DokHandlowe.WgDaty[warunek].Cast<DokumentHandlowy>().ToArray());
}
[Test]
[Description("W42: filtr po cesze na kolekcji SubTable pozycji dokumentu (dok.Pozycje[condition]) " +
"wykonuje się bez błędu i dla nieistniejącej cechy zwraca pusty zbiór.")]
public void FiltrPoCesze_NaPozycjachDokumentu_WykonujeSieBezBledu()
{
// Tworzymy dokument z jedną pozycją — sam dokument istnieje, ale żadna pozycja nie ma
// ustawionej (ani zdefiniowanej) testowej cechy.
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
InTransaction(() => DodajPozycje(dok, Towar(Towar_.Bikini), ilosc: 1, cena: 5));
// Filtr na kolekcji SubTable (dok.Pozycje[condition]) również wykonuje się serwerowo.
var warunek = new FieldCondition.Equal($"Features.{NieistniejacaCecha}", "S-2026-001");
var pozycje = dok.Pozycje[warunek].Cast<PozycjaDokHandlowego>().ToArray();
// Brak pozycji o takiej cesze — zbiór pusty, bez wyjątku.
pozycje.Should().BeEmpty();
}
// --- POMINIĘTE (W42 z trafieniami): filtr po cesze zwracający rekordy ---
// Powód: aby warunek FieldCondition.Equal("Features.Nazwa", wartość) zwrócił jakikolwiek
// dokument/pozycję, musi istnieć definicja cechy ORAZ zapisana wartość tej cechy na rekordzie.
// Oba elementy wymagałyby zdefiniowania własnej cechy (FeatureDefinition) i zapisu jej wartości,
// czego Demo nie gwarantuje. Testujemy więc jedynie, że konstrukcja i wykonanie warunku
// serwerowego są poprawne (powyżej), nie zaś zawartość zwróconego zbioru.
// --- POMINIĘTE (W40): przenoszenie cech z partii / dokumentu nadrzędnego ---
// Powód: przenoszenie cech to mechanizm KONFIGURACYJNY (flagi DefDokHandlowego.KopiujCechyDostawy,
// KopiujCechyDokumentu/KopiujCechyPozycji na definicji relacji), a faktyczne skopiowanie cechy
// wymaga: (1) istniejącej definicji cechy zarejestrowanej dla pozycji/partii, (2) zapisanego
// przyjęcia z ustawioną cechą i (3) rozchodu ze wskazaniem partii. Bez gwarantowanej definicji
// cechy w Demo nie da się zweryfikować przeniesienia wartości bezpieczną ścieżką, więc W40
// pomijamy w testach (pozostaje udokumentowany w skillu jako konfiguracja, nie API).
}