using System.Collections.ObjectModel; using Rozpisky.Data; using Rozpisky.Models; using Xunit; namespace Rozpisky.Tests; /// /// Slučování dodávané a uživatelské vrstvy číselníků a dopočet rozdílu /// ( / ). /// Na téhle logice stojí, jestli uživatel po aktualizaci programu najde svoje záznamy – /// chyba tady se projeví tichou ztrátou dat, kterou nikdo nenahlásí. /// public class CiselnikyVrstvyTesty { private static List Vychozi(params string[] jmena) => jmena.Select(j => new Jmeno { Hodnota = j }).ToList(); private static ObservableCollection Sluc( List vychozi, CiselnikyStore.Vrstva? uziv) { var cil = new ObservableCollection(); CiselnikyStore.Sluc(cil, vychozi, uziv); return cil; } [Fact] public void BezUzivatelskeVrstvyZustaneDodavanaBezeZmeny() { var vysledek = Sluc(Vychozi("Novák", "Svoboda"), null); Assert.Equal(new[] { "Novák", "Svoboda" }, vysledek.Select(j => j.Hodnota)); } [Fact] public void VlastniPolozkySeRadiZaDodavane() { var uziv = new CiselnikyStore.Vrstva { Vlastni = Vychozi("Dvořák") }; var vysledek = Sluc(Vychozi("Novák", "Svoboda"), uziv); Assert.Equal(new[] { "Novák", "Svoboda", "Dvořák" }, vysledek.Select(j => j.Hodnota)); } [Fact] public void SkrytaDodavanaPolozkaSeNeobjevi() { var uziv = new CiselnikyStore.Vrstva { Skryte = { "Svoboda" } }; var vysledek = Sluc(Vychozi("Novák", "Svoboda"), uziv); Assert.Equal(new[] { "Novák" }, vysledek.Select(j => j.Hodnota)); } [Fact] public void UpravenaDodavanaPolozkaSePrepiseNaSvemMiste() { // Uživatel opravil adresu dodávané organizace – musí zůstat na původní pozici, // jinak by se mu po každé aktualizaci přeházelo pořadí v našeptávači. var vychozi = new List { new() { Nazev = "SŽ Praha", Adresa = "stará" }, new() { Nazev = "SŽ Brno", Adresa = "Kounicova 26" }, }; var uziv = new CiselnikyStore.Vrstva { Vlastni = { new Organizace { Nazev = "SŽ Praha", Adresa = "Dlážděná 1003/7" } }, }; var cil = new ObservableCollection(); CiselnikyStore.Sluc(cil, vychozi, uziv); Assert.Equal(new[] { "SŽ Praha", "SŽ Brno" }, cil.Select(o => o.Nazev)); Assert.Equal("Dlážděná 1003/7", cil[0].Adresa); } [Fact] public void ParovaniIgnorujeVelikostPismen() { var uziv = new CiselnikyStore.Vrstva { Vlastni = Vychozi("NOVÁK") }; var vysledek = Sluc(Vychozi("Novák"), uziv); Assert.Single(vysledek); Assert.Equal("NOVÁK", vysledek[0].Hodnota); } [Fact] public void RozepsaneRadkySeNeslijouDoJednoho() { // Dva prázdné řádky přidané tlačítkem „Přidat záznam“ mají stejný (prázdný) klíč – // nesmí se spárovat, jinak by uživateli jeden zmizel dřív, než ho stihne vyplnit. var uziv = new CiselnikyStore.Vrstva { Vlastni = Vychozi("", "") }; var vysledek = Sluc(Vychozi("Novák"), uziv); Assert.Equal(3, vysledek.Count); } [Fact] public void RozdilZachytiPridaniUpravuISkryti() { var vychozi = Vychozi("Novák", "Svoboda", "Černý"); // Uživatel: Svobodu smazal, přidal Dvořáka, Novák zůstal beze změny. var stav = Vychozi("Novák", "Černý", "Dvořák"); var rozdil = CiselnikyStore.Rozdil(stav, vychozi); Assert.Equal(new[] { "Dvořák" }, rozdil.Vlastni.Select(j => j.Hodnota)); Assert.Equal(new[] { "Svoboda" }, rozdil.Skryte); } [Fact] public void RozdilNepovazujeNezmenenouPolozkuZaVlastni() { var vychozi = Vychozi("Novák", "Svoboda"); var rozdil = CiselnikyStore.Rozdil(Vychozi("Novák", "Svoboda"), vychozi); Assert.Empty(rozdil.Vlastni); Assert.Empty(rozdil.Skryte); } [Fact] public void RozdilZachytiZmenuJinehoNezKlicovehoPole() { var vychozi = new List { new() { Nazev = "EXprojekt s.r.o.", Telefon = "+420 533 312 000" }, }; var stav = new List { new() { Nazev = "EXprojekt s.r.o.", Telefon = "+420 111 222 333" }, }; var rozdil = CiselnikyStore.Rozdil(stav, vychozi); Assert.Single(rozdil.Vlastni); Assert.Equal("+420 111 222 333", rozdil.Vlastni[0].Telefon); Assert.Empty(rozdil.Skryte); // klíč zůstal, nejde o skrytí } [Fact] public void PrejmenovaniDodavanePolozkySeUloziJakoSkrytiAPridani() { var vychozi = Vychozi("Nowak"); var rozdil = CiselnikyStore.Rozdil(Vychozi("Novák"), vychozi); Assert.Equal(new[] { "Novák" }, rozdil.Vlastni.Select(j => j.Hodnota)); Assert.Equal(new[] { "Nowak" }, rozdil.Skryte); } [Fact] public void RozdilASlouceniDavajiZpetPuvodniStav() { // Kolečko uložit → načíst nesmí nic ztratit ani přidat, ať se s číselníkem stalo cokoli. var vychozi = Vychozi("Novák", "Svoboda", "Černý"); var stav = Vychozi("Novák", "Černý", "Dvořák", "Horák"); var vysledek = Sluc(vychozi, CiselnikyStore.Rozdil(stav, vychozi)); Assert.Equal(stav.Select(j => j.Hodnota), vysledek.Select(j => j.Hodnota)); } [Fact] public void NovaDodavanaPolozkaSePoAktualizaciObjeviAVlastniZustanou() { // Jádro celé změny: program vydá novou verzi s doplněným číselníkem, uživatelův // rozdíl je pořád ten starý – nová položka musí přibýt, vlastní nesmí zmizet. var stareVychozi = Vychozi("Novák"); var rozdilUzivatele = CiselnikyStore.Rozdil(Vychozi("Novák", "Dvořák"), stareVychozi); var noveVychozi = Vychozi("Novák", "Svoboda"); var vysledek = Sluc(noveVychozi, rozdilUzivatele); Assert.Equal(new[] { "Novák", "Svoboda", "Dvořák" }, vysledek.Select(j => j.Hodnota)); } [Fact] public void SkrytiPrezijeAktualizaciDodavaneVrstvy() { var stareVychozi = Vychozi("Novák", "Svoboda"); var rozdilUzivatele = CiselnikyStore.Rozdil(Vychozi("Novák"), stareVychozi); // Nová verze programu Svobodu pořád dodává – uživatel ho ale jednou odklidil. var vysledek = Sluc(Vychozi("Novák", "Svoboda", "Černý"), rozdilUzivatele); Assert.Equal(new[] { "Novák", "Černý" }, vysledek.Select(j => j.Hodnota)); } [Fact] public void UpravaDodavanePolozkyVMrizceSeZapiseDoRozdilu() { // Regrese: dodávané položky se dřív do mřížky vkládaly jako tytéž objekty, jaké držel // referenční snímek dodávané vrstvy. Úprava v mřížce mutovala i snímek, rozdíl se pak // počítal proti už změněným datům, vyšel prázdný a oprava se tiše ztratila. // Mazání a přidávání přitom fungovalo, takže se to snadno přehlédne. var dodavana = new List { new() { Nazev = "Jihomoravský" }, new() { Nazev = "Karlovarský" }, }; var vMrizce = new ObservableCollection(); CiselnikyStore.Sluc(vMrizce, dodavana, null); // Uživatel přepíše buňku v mřížce. vMrizce[1].Nazev = "Karlovarskýýýýý"; var rozdil = CiselnikyStore.Rozdil(vMrizce, dodavana); Assert.Equal(new[] { "Karlovarskýýýýý" }, rozdil.Vlastni.Select(k => k.Nazev)); Assert.Equal(new[] { "Karlovarský" }, rozdil.Skryte); // A po restartu programu tam ta úprava musí být. var poRestartu = new ObservableCollection(); CiselnikyStore.Sluc(poRestartu, dodavana, rozdil); Assert.Equal(new[] { "Jihomoravský", "Karlovarskýýýýý" }, poRestartu.Select(k => k.Nazev)); } [Fact] public void UpravaNemutujeDodavanouVrstvu() { var dodavana = new List { new() { Nazev = "SŽ Praha", Adresa = "Dlážděná 1003/7" } }; var vMrizce = new ObservableCollection(); CiselnikyStore.Sluc(vMrizce, dodavana, null); vMrizce[0].Adresa = "jiná adresa"; Assert.Equal("Dlážděná 1003/7", dodavana[0].Adresa); Assert.NotSame(dodavana[0], vMrizce[0]); } [Fact] public void KlicSeBerePodleTypuPolozky() { Assert.Equal("SŽ", CiselnikyStore.Klic(new Organizace { Nazev = "SŽ" })); Assert.Equal("EXprojekt", CiselnikyStore.Klic(new Firma { Nazev = "EXprojekt" })); Assert.Equal("Novák", CiselnikyStore.Klic(new Jmeno { Hodnota = "Novák" })); Assert.Equal("DPS", CiselnikyStore.Klic(new VerzeDokumentace { Hodnota = "DPS" })); Assert.Equal("D", CiselnikyStore.Klic(new Cast { Oznaceni = "D", Nazev = "Mosty" })); Assert.Equal("Jihomoravský", CiselnikyStore.Klic(new Kraj { Nazev = "Jihomoravský" })); } }