Przejdź do głównej treści
INF.04-02-25.06-SGCzerwiec 2025 · 30 kroków · ok. 85 min · 36 kryteriów z klucza

Rozwiązanie krok po kroku: Szyfr Cezara w aplikacjach (C# + WPF)

Rozwiązujemy arkusz z szyfrem Cezara w wersji C# + WPF: w konsoli metoda szyfrująca tekst przesunięciem liter o klucz (z zawijaniem alfabetu, kluczem ujemnym i większym niż 26), w oknie WPF ten sam szyfr z przyciskiem „Zaszyfruj” i zapisem wyniku do pliku przez systemowe okno „Zapisywanie jako”, a do tego pięć testów jednostkowych MSTest z tabeli 4 arkusza i dokument egzamin.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się cytatem wymagania, a kod pokazuje dokładnie te linie, które je spełniają. Metodę szyfrującą budujemy etapami i przy każdym etapie uruchamiamy program - widać, na czym polega błąd wersji bez zawijania i bez reszty z dzielenia klucza. Na końcu, w „Dobrych praktykach”, poprawiamy to, czego klucz nie sprawdza.

Co widać w podglądzie. Wyniki programu konsolowego i testów pochodzą z prawdziwego uruchomienia kodu z danego kroku (.NET 10, MSTest 4), a każdy wynik szyfrowania porównaliśmy z niezależnym wzorcem. Okno aplikacji to symulacja WPF w przeglądarce zbudowana z XAML danego kroku, a jej zachowanie odpowiada kodowi C# z kroku; każdy stan okna sprawdziliśmy na prawdziwym WPF - łącznie z oknem „Zapisywanie jako” i treścią zapisanego pliku.

Arkusz pozwala też na C++, Javę albo Pythona i inne biblioteki - ten wariant to jedna z możliwych dróg.

Jak liczą się punkty. Klucz ma 36 kryteriów (R.1.1 - R.4.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 punktów - można stracić 9 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Przygotowanie

    Krok 1 · po tym etapie masz 0 z 36 kryteriów (pkt)

    Krok 1: Folder zdającego i trzy podfoldery

    ok. 2 min
    Polecenie z arkusza

    Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsolowa, desktopowa, testy.

    Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim konsolowa, desktopowa i testy. W tym arkuszu zrzuty ekranu trafiają do folderu danej aplikacji (nie do osobnego folderu dokumentacji), a plik egzamin - bezpośrednio do folderu z numerem zdającego. Arkusz nie ma archiwum z materiałami.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-8 · po tym etapie masz 17 z 36 kryteriów (pkt)

    Krok 2: Projekt konsola w C#

    ok. 3 min
    Polecenie z arkusza

    Za pomocą narzędzi do tworzenia aplikacji konsolowych utwórz program implementujący algorytm szyfru Cezara. Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python. Podejście obiektowe lub strukturalne.

    Wybieramy C# i podejście strukturalne (jedna metoda statyczna). W Visual Studio: Aplikacja konsolowa, nazwa konsola. Klasa Program jest publiczna (public class) - z innego projektu (testów jednostkowych) będziemy wywoływać jej metodę szyfrującą, a klasa bez public byłaby tam niewidoczna.

    konsola/Program.cs C# nowy plik
    public class Program
    {
        static void Main()
        {
        }
    }
  3. Krok 3: Metoda Encrypt: dwa parametry, pętla po literach

    Kryteria: , , , ,

    R.2.1 Algorytm (nie musi być poprawny) jest zaimplementowany w funkcji lub metodzie zwracającej wartość typu napisowego

    R.2.2 Metoda/funkcja przyjmuje dwa parametry wejściowe typu napisowego i całkowitego, wartości tych parametrów zostały wczytane z klawiatury. Dopuszcza się w podejściu obiektowym metodę bezparametrową, jeśli tekst jawny i klucz są polami klasy

    R.2.3 Metoda/funkcja zawiera pętlę działającą na wszystkich literach tekstu jawnego (wejściowego)

    R.1.3 Użyte polskie lub angielskie nazewnictwo metod / funkcji. Nazewnictwo jest znaczące

    R.1.5 Zastosowane typy pasują do problemu, np. int, string

    ok. 3 min
    Polecenie z arkusza

    Szyfrowanie odbywa się w osobnej metodzie lub funkcji, która zawiera dwa argumenty - tekst jawny oraz klucz - i zwraca tekst zaszyfrowany.

    Szkielet metody: parametry string text i int key (R.2.2, R.1.5), wynik typu string (R.2.1). Pętla foreach przechodzi przez każdy znak tekstu (R.2.3) i na razie dokleja go do wyniku bez zmian - metoda zwraca tekst taki sam jak na wejściu. public static - metodę wywołamy bez tworzenia obiektu, także z testów.

    konsola/Program.cs C# zmienione: 10 linii
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            string result = "";
            foreach (char letter in text)
            {
                result += letter;
            }
            return result;
        }
    
        static void Main()
        {
        }
    }
  4. Krok 4: Program główny: tekst i klucz z klawiatury

    Kryteria:

    R.1.7 Program podejmuje zrozumiałą komunikację z użytkownikiem: komunikaty są znaczące, np. "Podaj tekst", "Podaj klucz"

    ok. 3 min
    Polecenie z arkusza

    Tekst oraz klucz są wczytywane z klawiatury w programie głównym. Sprawdź działanie metody lub funkcji. Program powinien nawiązać czytelną komunikację z użytkownikiem.

    Console.ReadLine() czyta wiersz z klawiatury, int.Parse zamienia klucz na liczbę. Wynik wypisujemy z komunikatem (R.1.7). Podgląd to prawdziwe uruchomienie: metoda jeszcze nie szyfruje, więc „abc” z kluczem 3 wychodzi bez zmian - to dobry moment, żeby sprawdzić, że program się kompiluje i komunikuje.

    konsola/Program.cs C# zmienione: 5 linii
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            string result = "";
            foreach (char letter in text)
            {
                result += letter;
            }
            return result;
        }
    
        static void Main()
        {
            Console.Write("Podaj tekst do zaszyfrowania: ");
            string text = Console.ReadLine();
            Console.Write("Podaj klucz: ");
            int key = int.Parse(Console.ReadLine());
            Console.WriteLine("Tekst zaszyfrowany: " + Encrypt(text, key));
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: abc
    Podaj klucz: 3
    Tekst zaszyfrowany: abc
  5. Krok 5: Przesunięcie litery o klucz, spacja bez zmian

    Kryteria: , ,

    R.2.4 Gdy klucz = 0, tekst nie jest zmieniany. Znak spacji nie jest szyfrowany

    R.2.5 Algorytm dla każdej litery tekstu wejściowego przesuwa ją o wartość klucza

    R.1.2 Kod zapisany z wcięciami dla zagnieżdżeń bloków

    ok. 3 min
    Polecenie z arkusza

    Szyfr Cezara polega na zamianie każdej litery tekstu jawnego na literę tekstu szyfrowanego przesuniętego w alfabecie o stałą liczbę znaków zwaną kluczem. Znak spacji pozostaje w zaszyfrowanym tekście bez zmian.

    Znak char to w C# liczba - kod w tablicy znaków ('a' = 97). letter + key przesuwa kod o klucz, a rzutowanie (char) zamienia wynik z powrotem na znak (R.2.5). Spację przepisujemy bez zmian (R.2.4).

    Podgląd: „abc” z kluczem 3 to „def” - dobrze. Ale „xyz” z kluczem 3 daje „{|}” - za literą z w tablicy znaków stoją nawiasy klamrowe, a nie znowu a. Brakuje zawijania alfabetu.

    konsola/Program.cs C# zmienione: 8 linii
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            string result = "";
            foreach (char letter in text)
            {
                if (letter == ' ')
                {
                    result += ' ';
                }
                else
                {
                    result += (char)(letter + key);
                }
            }
            return result;
        }
    
        static void Main()
        {
            Console.Write("Podaj tekst do zaszyfrowania: ");
            string text = Console.ReadLine();
            Console.Write("Podaj klucz: ");
            int key = int.Parse(Console.ReadLine());
            Console.WriteLine("Tekst zaszyfrowany: " + Encrypt(text, key));
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: abc
    Podaj klucz: 3
    Tekst zaszyfrowany: def
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: xyz
    Podaj klucz: 3
    Tekst zaszyfrowany: {|}
  6. Krok 6: Zawijanie alfabetu resztą z dzielenia

    Kryteria:

    R.2.6 Algorytm przy przesunięciu poza ostatnią/pierwszą literę alfabetu powoduje zawijanie (powrót do jego początku/końca) . Metoda dowolna, np. warunki, modulo, lub inne

    ok. 4 min
    Polecenie z arkusza

    Przykładowo dla klucza k = 3, każdą literę alfabetu z tabeli 1 należy zamienić odpowiednią literą z tabeli 2. Natomiast dla klucza k = -3, każdą literę alfabetu z tabeli 1 należy zamienić odpowiednią literą z tabeli 3.

    Liczymy na numerach liter jak w tabeli 1 (a = 0, ..., z = 25):

    • letter - 'a' - numer litery,
    • (position + key + 26) % 26 - przesunięcie z zawijaniem: reszta z dzielenia przez 26 sprowadza wynik do zakresu 0-25, więc po z (25) przychodzi znowu a (0) (R.2.6). Dodane 26 chroni klucz ujemny: w C# -1 % 26 daje -1, a nie 25,
    • (char)('a' + shifted) - z numeru z powrotem litera.

    Podgląd: „xyz” z kluczem 3 to „abc”, a „def” z kluczem -3 - „abc” (odszyfrowanie). Klucz 29 też już daje „def”, bo reszta z dzielenia zawija przesunięcie dodatnie. Ale klucz -29 wciąż daje dziwne znaki: suma 0 + (-29) + 26 jest ujemna, a reszta z dzielenia liczby ujemnej w C# też jest ujemna.

    konsola/Program.cs C# zmienione: 3 linie
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            string result = "";
            foreach (char letter in text)
            {
                if (letter == ' ')
                {
                    result += ' ';
                }
                else
                {
                    int position = letter - 'a';
                    int shifted = (position + key + 26) % 26;
                    result += (char)('a' + shifted);
                }
            }
            return result;
        }
    
        static void Main()
        {
            Console.Write("Podaj tekst do zaszyfrowania: ");
            string text = Console.ReadLine();
            Console.Write("Podaj klucz: ");
            int key = int.Parse(Console.ReadLine());
            Console.WriteLine("Tekst zaszyfrowany: " + Encrypt(text, key));
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: xyz
    Podaj klucz: 3
    Tekst zaszyfrowany: abc
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: def
    Podaj klucz: -3
    Tekst zaszyfrowany: abc
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: abc
    Podaj klucz: -29
    Tekst zaszyfrowany: ^_`
  7. Krok 7: Klucz większy niż długość alfabetu

    Kryteria: , , , ,

    R.2.7 Szyfr działa poprawnie dla klucza większego od długości alfabetu (np. klucz = klucz % 26 lub inna metoda )

    R.2.4 Gdy klucz = 0, tekst nie jest zmieniany. Znak spacji nie jest szyfrowany

    R.2.9 Po wprowadzeniu tekstu jawnego i wartości klucza w konsoli jest wyświetlany zaszyfrowany tekst (na zrzucie i obowiązkowo w kodzie)

    R.1.1 Kod źródłowy zapisany w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej

    R.1.4 Użyte polskie lub angielskie nazewnictwo pól lub zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli. Kryterium nie jest spełnione tylko wtedy, gdy zmienne nie istnieją lub ich nazwy nic nie znaczą, np. x, tab, tablica, foo, kolekcja

    ok. 3 min
    Polecenie z arkusza

    Klucz szyfrowania jest liczbą całkowitą (wartości dodatnie i ujemne, może być większy od 26). Dla klucza k = 0 tekst jawny jest równy tekstowi zaszyfrowanemu.

    Przesunięcie o 26 liter to pełne okrążenie alfabetu - nic nie zmienia. Dlatego na początku metody sprowadzamy klucz do zakresu od -25 do 25: key = key % 26 (29 → 3, -29 → -3) (R.2.7). Wtedy position + key + 26 jest zawsze nieujemne i zawijanie działa dla każdego klucza.

    Podgląd: „abc” z kluczem 29 to „def”, z kluczem -29 - „xyz”, a klucz 0 zostawia tekst bez zmian (R.2.4). To trzy zrzuty, o które prosi arkusz: klucz 0, ujemny i dodatni (R.2.9).

    konsola/Program.cs C# zmienione: 1 linia
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            key = key % 26;
            string result = "";
            foreach (char letter in text)
            {
                if (letter == ' ')
                {
                    result += ' ';
                }
                else
                {
                    int position = letter - 'a';
                    int shifted = (position + key + 26) % 26;
                    result += (char)('a' + shifted);
                }
            }
            return result;
        }
    
        static void Main()
        {
            Console.Write("Podaj tekst do zaszyfrowania: ");
            string text = Console.ReadLine();
            Console.Write("Podaj klucz: ");
            int key = int.Parse(Console.ReadLine());
            Console.WriteLine("Tekst zaszyfrowany: " + Encrypt(text, key));
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: abc
    Podaj klucz: 29
    Tekst zaszyfrowany: def
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: abc
    Podaj klucz: -29
    Tekst zaszyfrowany: xyz
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: ala ma kota
    Podaj klucz: 0
    Tekst zaszyfrowany: ala ma kota
  8. Krok 8: Zrzuty konsola1 - konsola3 i folder konsolowa

    Kryteria: , ,

    R.1.6 Podjęta próba uruchomienia kodu, co jest udokumentowane zrzutem przedstawiającym uruchomiony program lub jego kompilację

    R.2.8 Program uruchamia się w konsoli, co jest udokumentowane zrzutem ekranu

    R.4.8 Zapisany przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 4 min
    Polecenie z arkusza

    Po uruchomieniu programu wykonaj zrzuty ekranu dokumentujące interakcje programu dla różnych wartości klucza (0, ujemna, dodatnia). Zrzuty zapisz w folderze konsolowa pod nazwami konsola1.png, konsola2.png, itd. W folderze konsolowa powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, skopiowany z projektu plik z kodem źródłowym programu oraz plik wykonywalny, jeżeli istnieje.

    Trzy uruchomienia z Visual Studio i zrzut całego ekranu ze środowiskiem: klucz 0 (konsola1), ujemny (konsola2), dodatni (konsola3) - zrzuty w folderze konsolowa (R.1.6, R.2.8, R.4.8). Obok: konsola.zip z całym projektem, Program.cs i konsola.exe.

    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: ala ma kota
    Podaj klucz: 0
    Tekst zaszyfrowany: ala ma kota
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: def
    Podaj klucz: -3
    Tekst zaszyfrowany: abc
    
    > konsola.exe
    Podaj tekst do zaszyfrowania: xyz
    Podaj klucz: 3
    Tekst zaszyfrowany: abc
  9. Etap 3: Aplikacja desktopowa

    Kroki 9-17 · po tym etapie masz 28 z 36 kryteriów (pkt)

    Krok 9: Nowy projekt WPF desktopowa

    ok. 3 min
    Polecenie z arkusza

    Za pomocą dostępnego na stanowisku egzaminacyjnym środowiska programistycznego wykonaj aplikację desktopową będącą interfejsem graficznym programu utworzonego w konsoli.

    W Visual Studio: Utwórz nowy projekt → Aplikacja WPF, nazwa desktopowa. Wygląd w MainWindow.xaml, logika w MainWindow.xaml.cs.

    desktopowa/MainWindow.xaml XAML nowy plik
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
    
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# nowy plik
    using System.Windows;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  10. Krok 10: Tytuł, rozmiar i tło okna

    Kryteria: ,

    R.3.1 Utworzona aplikacja desktopowa z tytułem okna "Szyfrowanie. Wykonane przez" dalej wstawiony numer zdającego, aplikacja zawiera co najmniej jedną kontrolkę wynikającą z treści zadania

    R.3.3 Zastosowane kolory tła: CadetBlue (#5F9EA0) dla okna, LightBlue (#ADD8E6) dla przycisków

    ok. 2 min
    Polecenie z arkusza

    Tytuł okna „Szyfrowanie. Wykonane przez ”, dalej wstawiony numer zdającego. Kolor tła okna CadetBlue (#5F9EA0).

    Title z arkusza - na egzaminie po „Wykonane przez” wpisujemy numer PESEL, tu stoi Bartosz Bryniarski. Rozmiar jak na obrazie 1, tło kodem z arkusza.

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
    
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  11. Krok 11: Trzy kolumny i pole klucza

    Kryteria: ,

    R.3.2 W oknie zawarte: trzy napisy, pole edycyjne i wielowierszowe, pole do wypisywania szyfru i dwa przyciski

    R.3.4 Zastosowane kolory czcionki: AntiqueWhite (#FAEBD7) napisów (etykiet) , AliceBlue (#F0F8FF) dla pola z tekstem zaszyfrowanym

    ok. 3 min
    Polecenie z arkusza

    Kontrolki rozmieszczone zgodnie z obrazem 1, z określonym formatowaniem: napisy „Podaj wartość klucza”, „Podaj tekst”, „Tekst zaszyfrowany” w kolorze czcionki AntiqueWhite (#FAEBD7). Pole edycyjne do wprowadzania wartości klucza.

    Grid z trzema kolumnami: lewa (430 px) na pola, wąska środkowa na przycisk „Zaszyfruj”, prawa na wynik. W lewej StackPanel: etykieta (Label) z większą czcionką (FontSize="20") w kolorze AntiqueWhite, pod nią małe pole klucza keyTextBox - w pionowym panelu pole o stałej szerokości stoi na środku, jak na obrazie 1.

    desktopowa/MainWindow.xaml XAML zmienione: 9 linii
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  12. Krok 12: Pole wielowierszowe na tekst

    Kryteria:

    R.3.2 W oknie zawarte: trzy napisy, pole edycyjne i wielowierszowe, pole do wypisywania szyfru i dwa przyciski

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne wielowierszowe do wprowadzania tekstu z włączonym zawijaniem wierszy.

    Wielowierszowe pole to zwykły TextBox o dużej wysokości z TextWrapping="Wrap" - długi tekst przechodzi do kolejnego wiersza zamiast wychodzić poza pole. Druga etykieta „Podaj tekst” w tym samym stylu.

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
                <Label Content="Podaj tekst" FontSize="20" Foreground="#FAEBD7" Margin="5,30,0,0" />
                <TextBox x:Name="plainTextBox" Width="378" Height="275" Margin="0,30,0,0" TextWrapping="Wrap" />
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  13. Krok 13: Pole wyniku: ramka z zaokrąglonymi rogami

    Kryteria: ,

    R.3.2 W oknie zawarte: trzy napisy, pole edycyjne i wielowierszowe, pole do wypisywania szyfru i dwa przyciski

    R.3.4 Zastosowane kolory czcionki: AntiqueWhite (#FAEBD7) napisów (etykiet) , AliceBlue (#F0F8FF) dla pola z tekstem zaszyfrowanym

    ok. 3 min
    Polecenie z arkusza

    Pole, w którym wyświetlony jest zaszyfrowany tekst o cechach: kolor czcionki AliceBlue (#F0F8FF), obramowanie: linia ciągła koloru AntiqueWhite (#FAEBD7), rogi zaokrąglone.

    Wynik wypisujemy w TextBlock (tekst tylko do odczytu) w kolorze AliceBlue. Sam TextBlock nie ma ramki, dlatego obejmujemy go Border: BorderBrush to kolor linii, BorderThickness - grubość, a CornerRadius zaokrągla rogi.

    desktopowa/MainWindow.xaml XAML zmienione: 6 linii
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
                <Label Content="Podaj tekst" FontSize="20" Foreground="#FAEBD7" Margin="5,30,0,0" />
                <TextBox x:Name="plainTextBox" Width="378" Height="275" Margin="0,30,0,0" TextWrapping="Wrap" />
            </StackPanel>
            <StackPanel Grid.Column="2">
                <Label Content="Tekst zaszyfrowany" FontSize="20" Foreground="#FAEBD7" Margin="10,10,0,0" />
                <Border BorderBrush="#FAEBD7" BorderThickness="3" CornerRadius="25" Height="345" Margin="20,20,20,0">
                    <TextBlock x:Name="resultTextBlock" Foreground="#F0F8FF" FontSize="18" Margin="25,30" TextWrapping="Wrap" />
                </Border>
            </StackPanel>
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  14. Krok 14: Przyciski Zaszyfruj i Zapisz szyfr w pliku

    Kryteria: , ,

    R.3.2 W oknie zawarte: trzy napisy, pole edycyjne i wielowierszowe, pole do wypisywania szyfru i dwa przyciski

    R.3.3 Zastosowane kolory tła: CadetBlue (#5F9EA0) dla okna, LightBlue (#ADD8E6) dla przycisków

    R.3.7 W stanie początkowym aplikacja wyświetla wszystkie kontrolki rozmieszczone zgodnie z obrazem 1 arkusza egzaminacyjnego (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 2 min
    Polecenie z arkusza

    Przyciski o kolorze tła LightBlue (#ADD8E6).

    „Zaszyfruj” stoi w środkowej kolumnie (Grid.Column="1"); VerticalAlignment="Top" z górnym marginesem ustawia go na wysokości pola tekstu (bez tego WPF wyśrodkowałby przycisk w pionie). „Zapisz szyfr w pliku” stoi pod ramką wyniku. Oba z tłem LightBlue. Wygląd okna jest kompletny - porównaj z obrazem 1 (R.3.7).

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
                <Label Content="Podaj tekst" FontSize="20" Foreground="#FAEBD7" Margin="5,30,0,0" />
                <TextBox x:Name="plainTextBox" Width="378" Height="275" Margin="0,30,0,0" TextWrapping="Wrap" />
            </StackPanel>
            <StackPanel Grid.Column="2">
                <Label Content="Tekst zaszyfrowany" FontSize="20" Foreground="#FAEBD7" Margin="10,10,0,0" />
                <Border BorderBrush="#FAEBD7" BorderThickness="3" CornerRadius="25" Height="345" Margin="20,20,20,0">
                    <TextBlock x:Name="resultTextBlock" Foreground="#F0F8FF" FontSize="18" Margin="25,30" TextWrapping="Wrap" />
                </Border>
                <Button Content="Zapisz szyfr w pliku" Width="250" Height="35" Margin="0,30,0,0" Background="#ADD8E6" />
            </StackPanel>
            <Button Grid.Column="1" Content="Zaszyfruj" Width="72" Height="36" Margin="0,325,0,0" VerticalAlignment="Top" Background="#ADD8E6" />
        </Grid>
    </Window>
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  15. Krok 15: Zaszyfruj: metoda z konsoli i klucz domyślnie 0

    Kryteria: , ,

    R.3.5 Zdefiniowana przynajmniej jedna metoda obsługująca kliknięcie przycisku (może być pusta)

    R.3.6 Logika aplikacji jest obsłużona przy wykorzystaniu metody / funkcji szyfrującej

    R.3.8 Po wprowadzeniu tekstu i klucza oraz wybraniu przycisku „Zaszyfruj” zostaje wypisany tekst zaszyfrowany (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 4 min
    Polecenie z arkusza

    Klucz szyfrowania i tekst szyfrowany są pobierane z odpowiednich kontrolek. Szyfrowanie odbywa się po wprowadzeniu tekstu i klucza i wybraniu przycisku „Zaszyfruj”. Jeżeli w polu przeznaczonym na wpisanie klucza nie została wpisana wartość liczbowa całkowita, po naciśnięciu przycisku, do szyfrowania, należy zastosować wartość klucza 0. Do wykonania zadania można posłużyć się funkcją / metodą z aplikacji konsolowej.

    Metodę Encrypt kopiujemy z konsoli bez zmian (R.3.6). Obsługa przycisku:

    • int.TryParse(keyTextBox.Text, out int key) próbuje zamienić tekst na liczbę; gdy się nie uda (puste pole, litery, „3.5”), ustawia key na 0 i nie przerywa programu - dokładnie to, czego wymaga arkusz,
    • wynik szyfrowania trafia do resultTextBlock.Text (R.3.8).

    Wpisz w podglądzie klucz 3 i tekst „abc”, kliknij „Zaszyfruj” - „def” (obraz 2). Z kluczem „x” tekst zostaje bez zmian.

    Typowe błędy

    int.Parse zamiast TryParse przy pustym polu klucza rzuca wyjątek i zamyka aplikację.

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
                <Label Content="Podaj tekst" FontSize="20" Foreground="#FAEBD7" Margin="5,30,0,0" />
                <TextBox x:Name="plainTextBox" Width="378" Height="275" Margin="0,30,0,0" TextWrapping="Wrap" />
            </StackPanel>
            <StackPanel Grid.Column="2">
                <Label Content="Tekst zaszyfrowany" FontSize="20" Foreground="#FAEBD7" Margin="10,10,0,0" />
                <Border BorderBrush="#FAEBD7" BorderThickness="3" CornerRadius="25" Height="345" Margin="20,20,20,0">
                    <TextBlock x:Name="resultTextBlock" Foreground="#F0F8FF" FontSize="18" Margin="25,30" TextWrapping="Wrap" />
                </Border>
                <Button Content="Zapisz szyfr w pliku" Width="250" Height="35" Margin="0,30,0,0" Background="#ADD8E6" />
            </StackPanel>
            <Button Grid.Column="1" Content="Zaszyfruj" Width="72" Height="36" Margin="0,325,0,0" VerticalAlignment="Top" Background="#ADD8E6"
                    Click="EncryptButton_Click" />
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# zmienione: 26 linii
    using System.Windows;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private static string Encrypt(string text, int key)
        {
            key = key % 26;
            string result = "";
            foreach (char letter in text)
            {
                if (letter == ' ')
                {
                    result += ' ';
                }
                else
                {
                    int position = letter - 'a';
                    int shifted = (position + key + 26) % 26;
                    result += (char)('a' + shifted);
                }
            }
            return result;
        }
    
        private void EncryptButton_Click(object sender, RoutedEventArgs e)
        {
            int.TryParse(keyTextBox.Text, out int key);
            resultTextBlock.Text = Encrypt(plainTextBox.Text, key);
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  16. Krok 16: Zapis szyfru w pliku przez okno systemowe

    Kryteria: , ,

    R.3.5 Zdefiniowana przynajmniej jedna metoda obsługująca kliknięcie przycisku (może być pusta)

    R.3.9 Po wybraniu przycisku "Zapisz w pliku" pojawia się okno zapisywania do pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.3.10 W zapisanym pliku znajduje się tekst zwrócony funkcją szyfrującą niezależnie od jej poprawności

    ok. 4 min
    Polecenie z arkusza

    Po wybraniu przycisku „Zapisz szyfr w pliku”, zostanie otwarte systemowe okno dialogowe (obraz 3) do zapisu pliku. W pliku ma zostać zapisany zaszyfrowany tekst.

    Systemowe okno „Zapisywanie jako” to klasa SaveFileDialog z przestrzeni Microsoft.Win32 (dopisujemy using). Filter podpowiada typ pliku. ShowDialog() otwiera okno i czeka; zwraca true, gdy użytkownik kliknął „Zapisz” (a false przy „Anuluj” - wtedy nic nie zapisujemy). Pełna ścieżka wybranego pliku jest w FileName, a File.WriteAllText zapisuje do niego tekst z pola wyniku (R.3.9, R.3.10).

    W podglądzie okno zapisu jest uproszczone i niczego nie zapisuje na dysk; w prawdziwym WPF sprawdziliśmy, że plik powstaje i zawiera zaszyfrowany tekst.

    desktopowa/MainWindow.xaml XAML zmienione: 2 linie
    <Window x:Class="desktopowa.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:desktopowa"
            mc:Ignorable="d"
            Title="Szyfrowanie. Wykonane przez Bartosz Bryniarski" Height="555" Width="985"
            Background="#5F9EA0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="430" />
                <ColumnDefinition Width="120" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel>
                <Label Content="Podaj wartość klucza" FontSize="20" Foreground="#FAEBD7" Margin="5,10,0,0" />
                <TextBox x:Name="keyTextBox" Width="60" Height="20" Margin="0,20,0,0" />
                <Label Content="Podaj tekst" FontSize="20" Foreground="#FAEBD7" Margin="5,30,0,0" />
                <TextBox x:Name="plainTextBox" Width="378" Height="275" Margin="0,30,0,0" TextWrapping="Wrap" />
            </StackPanel>
            <StackPanel Grid.Column="2">
                <Label Content="Tekst zaszyfrowany" FontSize="20" Foreground="#FAEBD7" Margin="10,10,0,0" />
                <Border BorderBrush="#FAEBD7" BorderThickness="3" CornerRadius="25" Height="345" Margin="20,20,20,0">
                    <TextBlock x:Name="resultTextBlock" Foreground="#F0F8FF" FontSize="18" Margin="25,30" TextWrapping="Wrap" />
                </Border>
                <Button Content="Zapisz szyfr w pliku" Width="250" Height="35" Margin="0,30,0,0" Background="#ADD8E6"
                        Click="SaveButton_Click" />
            </StackPanel>
            <Button Grid.Column="1" Content="Zaszyfruj" Width="72" Height="36" Margin="0,325,0,0" VerticalAlignment="Top" Background="#ADD8E6"
                    Click="EncryptButton_Click" />
        </Grid>
    </Window>
    desktopowa/MainWindow.xaml.cs C# zmienione: 12 linii
    using System.IO;
    using System.Windows;
    using Microsoft.Win32;
    
    namespace desktopowa;
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private static string Encrypt(string text, int key)
        {
            key = key % 26;
            string result = "";
            foreach (char letter in text)
            {
                if (letter == ' ')
                {
                    result += ' ';
                }
                else
                {
                    int position = letter - 'a';
                    int shifted = (position + key + 26) % 26;
                    result += (char)('a' + shifted);
                }
            }
            return result;
        }
    
        private void EncryptButton_Click(object sender, RoutedEventArgs e)
        {
            int.TryParse(keyTextBox.Text, out int key);
            resultTextBlock.Text = Encrypt(plainTextBox.Text, key);
        }
    
        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "Plik tekstowy (*.txt)|*.txt";
            if (dialog.ShowDialog() == true)
            {
                File.WriteAllText(dialog.FileName, resultTextBlock.Text);
            }
        }
    }
    Okno aplikacji po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  17. Krok 17: Zrzuty desktop1 - desktop3 i folder desktopowa

    Kryteria:

    R.4.9 Zapisany przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji desktopowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 4 min
    Polecenie z arkusza

    Wykonaj zrzuty ekranu dokumentujące wszystkie stany aplikacji. Zrzuty zapisz w folderze desktopowa pod nazwami desktop1.png, desktop2.png, itd. W folderze desktopowa powinno znaleźć się archiwum całego projektu o nazwie desktopowa.zip, skopiowane z projektu pliki źródłowe, które były modyfikowane w czasie egzaminu oraz plik wykonywalny, jeżeli istnieje.

    Zrzuty całego ekranu ze środowiskiem: desktop1 - stan początkowy (obraz 1), desktop2 - po zaszyfrowaniu (obraz 2), desktop3 - otwarte okno „Zapisywanie jako” (obraz 3) - w folderze desktopowa (R.4.9). Obok: desktopowa.zip, MainWindow.xaml, MainWindow.xaml.cs, desktopowa.exe.

    Okno aplikacji bez zmian - taki jak po kroku 16.

  18. Etap 4: Testy jednostkowe

    Kroki 18-28 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 18: Projekt testów MSTest

    ok. 3 min
    Polecenie z arkusza

    Wykonaj testy jednostkowe funkcji lub metody realizującej szyfr Cezara z aplikacji konsolowej. Do napisania testów wykorzystaj dostępną na stanowisku egzaminacyjnym bibliotekę do testów jednostkowych dla języka programowania, w którym została napisana aplikacja konsolowa.

    Dla C# w Visual Studio jest gotowy szablon Projekt testowy MSTest (dotnet new mstest -n testy). Dodajemy go do rozwiązania obok projektu konsola. Szablon tworzy przykładowy plik Test1.cs - usuwamy go, a na jego miejsce zakładamy CaesarTests.cs z pustą klasą testów oznaczoną atrybutem [TestClass].

    testy/CaesarTests.cs C# nowy plik
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
    }
    testy/testy.csproj Projekt C# nowy plik
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net10.0</TargetFramework>
        <LangVersion>latest</LangVersion>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="MSTest" Version="4.0.1" />
      </ItemGroup>
    
      <ItemGroup>
        <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
      </ItemGroup>
    
    </Project>
    Wynik programu po tym kroku
    > dotnet new mstest -n testy
    Szablon „Projekt testowy MSTest” został pomyślnie utworzony.
  19. Krok 19: Odwołanie do projektu konsola

    ok. 2 min
    Polecenie z arkusza

    Metody testujące należy zapisać w oddzielnym pliku w lokalizacji zgodnej z wymaganiami danego języka programowania i wykorzystanej biblioteki do zapisu testów jednostkowych.

    Testy mają wywoływać prawdziwą metodę Encrypt z konsoli, a nie jej kopię. W Visual Studio: prawy przycisk na projekcie testy → Dodaj → Odwołanie do projektu → konsola. W pliku projektu pojawia się ProjectReference. Dzięki temu, że klasa Program i metoda Encrypt są publiczne, test zobaczy Program.Encrypt.

    testy/testy.csproj Projekt C# zmienione: 4 linie
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net10.0</TargetFramework>
        <LangVersion>latest</LangVersion>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="MSTest" Version="4.0.1" />
      </ItemGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\konsola\konsola.csproj" />
      </ItemGroup>
    
      <ItemGroup>
        <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
      </ItemGroup>
    
    </Project>

    Wynik programu bez zmian - taki jak po kroku 18.

  20. Krok 20: Test 1: Dane podstawowe

    Kryteria: ,

    R.4.3 Zapisany test jednostkowy 1, który przy danych wejściowych abc, 3 oczekuje wyniku def

    R.4.1 Zapisana co najmniej jedna metoda testująca, w której została wykorzystana asercja, zastosowane nazwy odzwierciedlające cel testu

    ok. 2 min
    Polecenie z arkusza

    Tabela 4. Test 1: Dane podstawowe (klucz dodatni, wartość mniejsza od długości alfabetu). Dane wejściowe: tekst jawny „abc”, klucz 3. Oczekiwana wartość po zaszyfrowaniu: „def”. Każdy przypadek testowy powinien być sprawdzany za pomocą asercji oddzielną metodą.

    Test 1 z tabeli 4: „Dane podstawowe (klucz dodatni, wartość mniejsza od długości alfabetu)”. Metoda testująca ma atrybut [TestMethod], a nazwę według konwencji C# Metoda_Warunek_OczekiwanyWynik, która mówi, co sprawdza. Assert.AreEqual(oczekiwane, rzeczywiste) porównuje wynik metody Program.Encrypt("abc", 3) z wartością „def” - przy różnicy test kończy się niepowodzeniem. Każdy przypadek to osobna metoda, jak wymaga arkusz.

    testy/CaesarTests.cs C# zmienione: 5 linii
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
        [TestMethod]
        public void Encrypt_PositiveKey_ShiftsLetters()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 3));
        }
    }

    Wynik programu bez zmian - taki jak po kroku 18.

  21. Krok 21: Test 2: „Zawijanie”

    Kryteria:

    R.4.4 Zapisany test jednostkowy 2, który przy danych wejściowych xyz, 3 oczekuje wyniku abc

    ok. 2 min
    Polecenie z arkusza

    Tabela 4. Test 2: „Zawijanie” (gdy litery w tekście i klucz wychodzą poza alfabet). Dane wejściowe: tekst jawny „xyz”, klucz 3. Oczekiwana wartość po zaszyfrowaniu: „abc”. Każdy przypadek testowy powinien być sprawdzany za pomocą asercji oddzielną metodą.

    Test 2 z tabeli 4: „„Zawijanie” (gdy litery w tekście i klucz wychodzą poza alfabet)” - Program.Encrypt("xyz", 3) ma dać „abc”. Ten sam wzór, osobna metoda z nazwą mówiącą o celu testu.

    testy/CaesarTests.cs C# zmienione: 6 linii
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
        [TestMethod]
        public void Encrypt_PositiveKey_ShiftsLetters()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 3));
        }
    
        [TestMethod]
        public void Encrypt_LettersPastZ_WrapToStart()
        {
            Assert.AreEqual("abc", Program.Encrypt("xyz", 3));
        }
    }

    Wynik programu bez zmian - taki jak po kroku 18.

  22. Krok 22: Test 3: Odszyfrowanie

    Kryteria:

    R.4.5 Zapisany test jednostkowy 3, który przy danych wejściowych def, -3 oczekuje wyniku abc

    ok. 2 min
    Polecenie z arkusza

    Tabela 4. Test 3: Odszyfrowanie (klucz ujemny). Dane wejściowe: tekst jawny „def”, klucz -3. Oczekiwana wartość po zaszyfrowaniu: „abc”. Każdy przypadek testowy powinien być sprawdzany za pomocą asercji oddzielną metodą.

    Test 3 z tabeli 4: „Odszyfrowanie (klucz ujemny)” - Program.Encrypt("def", -3) ma dać „abc”. Ten sam wzór, osobna metoda z nazwą mówiącą o celu testu.

    testy/CaesarTests.cs C# zmienione: 6 linii
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
        [TestMethod]
        public void Encrypt_PositiveKey_ShiftsLetters()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 3));
        }
    
        [TestMethod]
        public void Encrypt_LettersPastZ_WrapToStart()
        {
            Assert.AreEqual("abc", Program.Encrypt("xyz", 3));
        }
    
        [TestMethod]
        public void Encrypt_NegativeKey_Decrypts()
        {
            Assert.AreEqual("abc", Program.Encrypt("def", -3));
        }
    }

    Wynik programu bez zmian - taki jak po kroku 18.

  23. Krok 23: Test 4: Klucz większy niż długość alfabetu

    Kryteria:

    R.4.6 Zapisany test jednostkowy 4, który przy danych wejściowych abc, 29 oczekuje wyniku def

    ok. 2 min
    Polecenie z arkusza

    Tabela 4. Test 4: Klucz większy niż długość alfabetu. Dane wejściowe: tekst jawny „abc”, klucz 29. Oczekiwana wartość po zaszyfrowaniu: „def”. Każdy przypadek testowy powinien być sprawdzany za pomocą asercji oddzielną metodą.

    Test 4 z tabeli 4: „Klucz większy niż długość alfabetu” - Program.Encrypt("abc", 29) ma dać „def”. Ten sam wzór, osobna metoda z nazwą mówiącą o celu testu.

    testy/CaesarTests.cs C# zmienione: 6 linii
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
        [TestMethod]
        public void Encrypt_PositiveKey_ShiftsLetters()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 3));
        }
    
        [TestMethod]
        public void Encrypt_LettersPastZ_WrapToStart()
        {
            Assert.AreEqual("abc", Program.Encrypt("xyz", 3));
        }
    
        [TestMethod]
        public void Encrypt_NegativeKey_Decrypts()
        {
            Assert.AreEqual("abc", Program.Encrypt("def", -3));
        }
    
        [TestMethod]
        public void Encrypt_KeyGreaterThanAlphabet_ShiftsByRemainder()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 29));
        }
    }

    Wynik programu bez zmian - taki jak po kroku 18.

  24. Krok 24: Test 5: Spacja w tekście

    Kryteria:

    R.4.7 Zapisany test jednostkowy 5, który przy danych wejściowych ab cd, 2 oczekuje wyniku cd ef

    ok. 2 min
    Polecenie z arkusza

    Tabela 4. Test 5: Spacja w tekście. Dane wejściowe: tekst jawny „ab cd”, klucz 2. Oczekiwana wartość po zaszyfrowaniu: „cd ef”. Każdy przypadek testowy powinien być sprawdzany za pomocą asercji oddzielną metodą.

    Test 5 z tabeli 4: „Spacja w tekście” - Program.Encrypt("ab cd", 2) ma dać „cd ef”. Ten sam wzór, osobna metoda z nazwą mówiącą o celu testu.

    testy/CaesarTests.cs C# zmienione: 6 linii
    namespace testy;
    
    [TestClass]
    public sealed class CaesarTests
    {
        [TestMethod]
        public void Encrypt_PositiveKey_ShiftsLetters()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 3));
        }
    
        [TestMethod]
        public void Encrypt_LettersPastZ_WrapToStart()
        {
            Assert.AreEqual("abc", Program.Encrypt("xyz", 3));
        }
    
        [TestMethod]
        public void Encrypt_NegativeKey_Decrypts()
        {
            Assert.AreEqual("abc", Program.Encrypt("def", -3));
        }
    
        [TestMethod]
        public void Encrypt_KeyGreaterThanAlphabet_ShiftsByRemainder()
        {
            Assert.AreEqual("def", Program.Encrypt("abc", 29));
        }
    
        [TestMethod]
        public void Encrypt_TextWithSpace_KeepsSpace()
        {
            Assert.AreEqual("cd ef", Program.Encrypt("ab cd", 2));
        }
    }

    Wynik programu bez zmian - taki jak po kroku 18.

  25. Krok 25: Uruchomienie testów

    Kryteria:

    R.4.2 Co najmniej 1 metoda testująca porównuje wartość oczekiwaną z wartością zwracaną przez metodę szyfrującą i jest ona uruchomiona, co jest udokumentowane zrzutem ekranowym

    ok. 3 min
    Polecenie z arkusza

    Po napisaniu metod testujących, uruchom wszystkie metody. Wykonaj zrzut/zrzuty ekranu dokumentujące uruchomienie testów, zrzuty zapisz w folderze testy pod nazwami test1.png, test2.png, itd.

    W Visual Studio: Test → Eksplorator testów → Uruchom wszystkie testy (w terminalu: dotnet test w folderze testy). Obok prawdziwy wynik: wszystkie pięć testów przechodzi (R.4.2). Zrzut całego ekranu z Eksploratorem testów i zielonymi znacznikami - test1.png w folderze testy.

    Wynik programu po tym kroku
    > dotnet test
      Powodzenie Encrypt_KeyGreaterThanAlphabet_ShiftsByRemainder [8 ms]
      Powodzenie Encrypt_NegativeKey_Decrypts [8 ms]
      Powodzenie Encrypt_PositiveKey_ShiftsLetters [8 ms]
      Powodzenie Encrypt_TextWithSpace_KeepsSpace [8 ms]
      Powodzenie Encrypt_LettersPastZ_WrapToStart [8 ms]
    Przebieg testu zakończony powodzeniem.
    Łączna liczba testów: 5
         Zakończone pomyślnie: 5
     Łączny czas: 0,6137 Sekundy
  26. Krok 26: Co pokażą testy, gdy w szyfrze brakuje zawijania

    ok. 2 min
    Polecenie z arkusza

    Jeżeli metoda szyfrująca została napisana w części I niepoprawnie, testy powinny wykazać błędy. W tej części egzaminu ocenie podlegać będzie zapis i uruchomienie testu, a nie metoda szyfrująca.

    Po to są testy: wynik obok to prawdziwe uruchomienie tych samych testów na wersji metody z kroku „Przesunięcie litery o klucz” - bez zawijania alfabetu. Przechodzą tylko testy, w których litery nie wychodzą poza z ani przed a (abc z kluczem 3, def z kluczem -3, spacja). Testy zawijania i klucza 29 kończą się niepowodzeniem, a MSTest pokazuje, czego oczekiwano i co metoda zwróciła („{|}” zamiast „abc”) - od razu widać, gdzie szukać błędu. Dla klucza 29 zamiast liter wychodzą znaki sterujące z tablicy znaków (kody 127 i 128) - MSTest pokazuje je symbolami zastępczymi.

    Na egzaminie testy mają pokazać prawdę: niepowodzenie przy błędnej metodzie to poprawnie wykonana część III. Nie zmieniaj testów pod błędną metodę.

    Wynik programu po tym kroku
    > dotnet test
      Powodzenie Encrypt_NegativeKey_Decrypts [17 ms]
      Powodzenie Encrypt_TextWithSpace_KeepsSpace [17 ms]
      Powodzenie Encrypt_PositiveKey_ShiftsLetters [17 ms]
      Niepowodzenie Encrypt_LettersPastZ_WrapToStart [61 ms]
      Komunikat o błędzie:
       Assert.AreEqual — niepowodzenie. Długości ciągów są 3, ale różnią się w indeksie 0. Wyrażenie „expected”: „"abc"”, wyrażenie „actual”: „Program.Encrypt("xyz", 3)”.
    Oczekiwane: "abc"
    Ale było:   "{|}"
    -------------^
      Niepowodzenie Encrypt_KeyGreaterThanAlphabet_ShiftsByRemainder [61 ms]
      Komunikat o błędzie:
       Assert.AreEqual — niepowodzenie. Długości ciągów są 3, ale różnią się w indeksie 0. Wyrażenie „expected”: „"def"”, wyrażenie „actual”: „Program.Encrypt("abc", 29)”.
    Oczekiwane: "def"
    Ale było:   "~⑿⒀"
    -------------^
    Łączna liczba testów: 5
         Zakończone pomyślnie: 3
         Zakończone niepowodzeniem: 2
     Łączny czas: 1,6837 Sekundy
  27. Krok 27: Folder testy: pliki, zrzut i archiwum

    ok. 2 min
    Polecenie z arkusza

    W folderze testy zapisz bezpośrednio pliki, których treść była modyfikowana oraz zrzuty ekranu. Utwórz archiwum ZIP zawierające cały projekt i zapisz je w folderze testy.

    W folderze testy: CaesarTests.cs, testy.csproj (zmieniony o odwołanie do konsoli), test1.png i archiwum ZIP całego rozwiązania z projektami konsola i testy - bez konsoli projekt testów się nie zbuduje.

    Wynik programu bez zmian - taki jak po kroku 26.

  28. Krok 28: Plik egzamin

    Kryteria:

    R.4.10 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania (stosowanych przez zdającego) . Na płycie wszystkie wykonane projekty są spakowane oraz umieszczone pliki źródłowe i pliki wykonywalne (jeśli istnieją) na zewnątrz archiwów

    ok. 2 min
    Polecenie z arkusza

    Utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać informacje o narzędziach wykorzystanych na egzaminie: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania. Dokument egzamin zapisz w folderze z numerem zdającego.

    Plik egzamin w folderze z numerem zdającego (nie w podfolderze) z trzema informacjami o narzędziach (R.4.10).

    egzamin.txt Tekst nowy plik
    System operacyjny: Windows 11
    Środowisko programistyczne: Visual Studio 2022 (aplikacja konsolowa, desktopowa i testy)
    Języki programowania: C# (konsola, testy MSTest), C# i XAML - WPF (aplikacja desktopowa)

    Wynik programu bez zmian - taki jak po kroku 26.

  29. Etap 5: Dobre praktyki (poza kluczem)

    Krok 29 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 29: Konsola: bezpieczny klucz i znaki spoza alfabetu

    ok. 4 min
    Polecenie z arkusza

    Nie jest wymagana walidacja tekstu jawnego – zakłada się, że wprowadzono go bez błędów (tylko małe litery i spacje).

    Arkusz zakłada poprawne dane, ale prawdziwy użytkownik wpisze wielką literę, kropkę albo słowo zamiast klucza:

    • int.TryParse w pętli - klucz podany jako „trzy” nie przerywa programu wyjątkiem, tylko prosi o liczbę ponownie,
    • warunek letter < 'a' || letter > 'z' przepuszcza bez zmian wszystko spoza małych liter (spację, wielkie litery, kropki, cyfry). Wersja z egzaminu zamieniłaby „Ala” na nieczytelne znaki, bo liczy numer litery także dla 'A'.

    Testy z tabeli 4 nadal przechodzą - spacja jest jednym z przepuszczanych znaków. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    konsola/Program.cs C# zmienione: 8 linii
    public class Program
    {
        public static string Encrypt(string text, int key)
        {
            key = key % 26;
            string result = "";
            foreach (char letter in text)
            {
                if (letter < 'a' || letter > 'z')
                {
                    result += letter;   // spacja i znaki spoza alfabetu bez zmian
                }
                else
                {
                    int position = letter - 'a';
                    int shifted = (position + key + 26) % 26;
                    result += (char)('a' + shifted);
                }
            }
            return result;
        }
    
        static void Main()
        {
            Console.Write("Podaj tekst do zaszyfrowania: ");
            string text = Console.ReadLine();
            Console.Write("Podaj klucz: ");
            int key;
            while (!int.TryParse(Console.ReadLine(), out key))
            {
                Console.Write("Klucz musi być liczbą całkowitą. Podaj klucz: ");
            }
            // int key = int.Parse(Console.ReadLine());
            Console.WriteLine("Tekst zaszyfrowany: " + Encrypt(text, key));
        }
    }
    Wynik programu po tym kroku
    > konsola.exe
    Podaj tekst do zaszyfrowania: ala ma kota.
    Podaj klucz: 3
    Tekst zaszyfrowany: dod pd nrwd.
  30. Etap 6: Oddanie pracy

    Krok 30 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 30: Nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    UWAGA: Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny znajdować się podfoldery desktopowa, konsolowa, testy oraz plik egzamin.

    Sprawdzamy zawartość przed nagraniem:

    • konsolowa: konsola.zip, Program.cs, konsola.exe, konsola1.png - konsola3.png,
    • desktopowa: desktopowa.zip, MainWindow.xaml, MainWindow.xaml.cs, desktopowa.exe, desktop1.png - desktop3.png,
    • testy: archiwum projektu z testami, CaesarTests.cs, testy.csproj, test1.png,
    • plik egzamin w folderze głównym.

    Wszystkie projekty spakowane, źródła i pliki wykonywalne obok archiwów. Nagrywamy, sprawdzamy odczyt płyty, opisujemy ją numerem zdającego.

    Wynik programu bez zmian - taki jak po kroku 29.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony). Treść arkusza i klucza oceniania pochodzi z CKE.