diff --git a/.github/workflows/dotnet-desktop.yml b/.github/workflows/dotnet-desktop.yml new file mode 100644 index 0000000..fff9e2e --- /dev/null +++ b/.github/workflows/dotnet-desktop.yml @@ -0,0 +1,143 @@ +name: .NET Tests & Auto-commit + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches-ignore: [main] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + issues: read + +jobs: + + check-target: + runs-on: ubuntu-latest + outputs: + pr_valid: ${{ steps.check.outputs.pr_valid }} + steps: + - name: 🚫 Проверка PR в main + id: check + shell: bash + run: | + PR_BASE="${{ github.event.pull_request.base.ref }}" + echo "Base branch: $PR_BASE" + if [ "$PR_BASE" = "main" ]; then + echo "❌ Нельзя отправлять работу в main ветку." + echo "pr_valid=false" >> $GITHUB_OUTPUT + exit 1 + else + echo "✅ PR направлен в '$PR_BASE', можно запускать тесты." + echo "pr_valid=true" >> $GITHUB_OUTPUT + fi + + tests: + name: Run test + runs-on: windows-latest + needs: check-target + if: | + (github.event_name == 'pull_request' && needs.check-target.outputs.pr_valid == 'true') || + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' + strategy: + matrix: + configuration: [Debug] + + steps: + - name: Checkout code safely + uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + ref: ${{ github.event.pull_request.head.sha || github.ref }} + fetch-depth: 0 + + - name: Install .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + 9.0.x + + - name: Setup MSBuild.exe + uses: microsoft/setup-msbuild@v2 + + - name: Restore + run: dotnet restore Lab9/Lab9.sln + + - name: Build + run: dotnet build Lab9/Lab9.sln --configuration ${{ matrix.configuration }} --no-restore + + - name: Run tests (league cascade) + id: cascade + shell: pwsh + env: + CFG: ${{ matrix.configuration }} + run: | + $testProjectPath = "Lab9Test/Lab9Test.csproj" + $testDir = "Lab9Test" + + Write-Host "Building test project..." + dotnet build $testProjectPath -c $Env:CFG --no-restore + + $tfm = (dotnet list $testProjectPath framework --framework net9.0 | Select-Object -Last 1).Trim() + if (-not $tfm) { $tfm = "net9.0" } + + $dll = Join-Path $PWD "$testDir\bin\$Env:CFG\$tfm\Lab9Test.dll" + + Write-Host "Ожидаемая DLL: $dll" + + if (-not (Test-Path $dll)) { + Write-Error "DLL не найдена: $dll" + Write-Host "`nСодержимое bin папки:" + Get-ChildItem "$testDir\bin" -Recurse -ErrorAction SilentlyContinue | + Select-Object FullName | Out-Host + exit 1 + } + + Write-Host "DLL успешно найдена`n" + + $leagues = @{ + "Purple" = @("Task1","Task2","Task3","Task4") + "Blue" = @("Task1","Task2","Task3","Task4") + "Green" = @("Task1","Task2","Task3","Task4") + "White" = @("Task1","Task2","Task3","Task4") + } + + foreach ($leagueName in $leagues.Keys) { + Write-Host "Лига: $leagueName" + $allPassed = $true + + foreach ($cls in $leagues[$leagueName]) { + $filter = "FullyQualifiedName~$leagueName.$cls" + Write-Host " Запуск: $leagueName.$cls" + + dotnet vstest $dll --TestCaseFilter:"$filter" --Logger:"trx;LogFileName=test-$leagueName-$cls.trx" + + if ($LASTEXITCODE -ne 0) { + Write-Host " ❌ $leagueName.$cls не прошёл" -ForegroundColor Red + $allPassed = $false + } else { + Write-Host " ✅ $leagueName.$cls прошёл" -ForegroundColor Green + } + } + + if ($allPassed) { + Write-Host "✅ Все тесты лиги $leagueName прошли! Останавливаем каскад." -ForegroundColor Green + exit 0 + } else { + Write-Host "⚠️ Лига $leagueName не прошла полностью. Переходим к следующей..." -ForegroundColor Yellow + } + } + + Write-Host "❌ Ни одна лига полностью не прошла." -ForegroundColor Red + exit 1 + + - name: Upload TRX + if: always() + uses: actions/upload-artifact@v4 + with: + name: trx-${{ matrix.configuration }} + path: '**/test-*.trx' diff --git a/Lab9/Blue/Blue.cs b/Lab9/Blue/Blue.cs index ad43172..8c81a99 100644 --- a/Lab9/Blue/Blue.cs +++ b/Lab9/Blue/Blue.cs @@ -1,3 +1,14 @@ namespace Lab9.Blue { + public abstract class Blue + { + public string Input { get; protected set; } + protected Blue(string input) => Input = input; + public abstract void Review(); + public virtual void ChangeText(string text) + { + Input = text; + Review(); + } + } } \ No newline at end of file diff --git a/Lab9/Blue/Task1.cs b/Lab9/Blue/Task1.cs new file mode 100644 index 0000000..573d0b1 --- /dev/null +++ b/Lab9/Blue/Task1.cs @@ -0,0 +1,62 @@ +namespace Lab9.Blue +{ + public class Task1 : Blue + { + public Task1(string input) : base(input) {} + public string[] Output { get; protected set; } + public override void Review() + { + if (Input == null) + { + Output = null; + return; + } + string[] words = Input.Split(' ', StringSplitOptions.RemoveEmptyEntries); + string current = ""; + int count = 0; + foreach (var i in words) + { + if (current.Length == 0) + { + current += i; + } + else if (current.Length != 0 && current.Length + 1 + i.Length <= 50) + { + current += " " + i; + } + else + { + count++; + current = i; + } + } + if (current.Length > 0) count++; + + Output = new string[count]; + int ind = 0; + current = ""; + foreach (var i in words) + { + if (current.Length == 0) + { + current += i; + } + else if (current.Length + 1 + i.Length <= 50) + { + current += " " + i; + } + else + { + Output[ind++] = current; + current = i; + } + } + if (current.Length > 0) Output[ind] = current; + } + public override string ToString() + { + return string.Join(Environment.NewLine, Output); + } + + } +} \ No newline at end of file diff --git a/Lab9/Blue/Task2.cs b/Lab9/Blue/Task2.cs new file mode 100644 index 0000000..61bdaf9 --- /dev/null +++ b/Lab9/Blue/Task2.cs @@ -0,0 +1,90 @@ +namespace Lab9.Blue +{ + public class Task2 : Blue + { + private string _sequence; + + public Task2(string input, string sequence) : base(input) + { + _sequence = sequence; + } + public string Output { get; private set; } + public override string ToString() => Output ?? ""; + public override void Review() + { + if (Input == null || _sequence == null) + { + Output = Input; + return; + } + string[] parts = Input.Split(' ', StringSplitOptions.RemoveEmptyEntries); + int length = 0; + foreach (string part in parts) + { + int start = 0; + while (start < part.Length && !IsWordChar(part[start])) + start++; + int end = part.Length - 1; + while (end >= 0 && !IsWordChar(part[end])) + end--; + if (start > end) + { + length++; + continue; + } + + string prefix = part.Substring(0, start); + string word = part.Substring(start, end - start + 1); + string suffix = part.Substring(end + 1); + + if (word.Contains(_sequence, StringComparison.OrdinalIgnoreCase)) + { + string newPart = prefix + suffix; + if (newPart.Length > 0) length++; + } + else length++; + } + + string[] result = new string[length]; + int ind = 0; + foreach (string part in parts) + { + int start = 0; + while (start < part.Length && !IsWordChar(part[start])) + start++; + int end = part.Length - 1; + while (end >= 0 && !IsWordChar(part[end])) + end--; + if (start > end) + { + result[ind++] = part; + continue; + } + + string prefix = part.Substring(0, start); + string word = part.Substring(start, end - start + 1); + string suffix = part.Substring(end + 1); + + if (word.Contains(_sequence, StringComparison.OrdinalIgnoreCase)) + { + string newPart = prefix + suffix; + if (newPart.Length > 0) result[ind++] = newPart; + } + else result[ind++] = part; + } + + Output = String.Join(" ", result); + Output = Output.Replace(" .", "."); + Output = Output.Replace(" ,", ","); + Output = Output.Replace(" !", "!"); + Output = Output.Replace(" ?", "?"); + Output = Output.Replace(" :", ":"); + Output = Output.Replace(" ;", ";"); + } + private bool IsWordChar(char c) + { + return char.IsLetter(c) || c == '-' || c == '\''; + } + + } +} \ No newline at end of file diff --git a/Lab9/Blue/Task3.cs b/Lab9/Blue/Task3.cs new file mode 100644 index 0000000..c1b697a --- /dev/null +++ b/Lab9/Blue/Task3.cs @@ -0,0 +1,83 @@ +namespace Lab9.Blue +{ + public class Task3 : Blue + { + public Task3(string input) : base(input) {} + public (char, double)[] Output { get; private set; } + + public override string ToString() + { + if (Output == null) return ""; + string[] lines = new string[Output.Length]; + + for (int i = 0; i < Output.Length; i++) + { + lines[i] = $"{Output[i].Item1}:{Output[i].Item2:F4}"; + } + + return string.Join(Environment.NewLine, lines); + } + + public override void Review() + { + if (Input == null) + { + Output = null; + return; + } + int wordCount = 0; + for (int i = 0; i < Input.Length; i++) + { + if (IsWordStart(Input, i)) wordCount++; + + } + char[] firstLetters = new char[wordCount]; + int index = 0; + for (int i = 0; i < Input.Length; i++) + { + if (IsWordStart(Input, i)) + { + char c = char.ToLower(Input[i]); + firstLetters[index++] = c; + } + } + + char[] uniqueLetters = firstLetters.Distinct().ToArray(); + + int[] counts = new int[uniqueLetters.Length]; + for (int i = 0; i < uniqueLetters.Length; i++) + { + for (int j = 0; j < firstLetters.Length; j++) + { + if (uniqueLetters[i] == firstLetters[j]) + counts[i]++; + } + } + + Output = new (char, double)[uniqueLetters.Length]; + for (int i = 0; i < uniqueLetters.Length; i++) + { + double percent = counts[i] * 100.0 / firstLetters.Length; + Output[i] = (uniqueLetters[i], percent); + } + + Output = Output + .OrderByDescending(x => x.Item2) + .ThenBy(x => x.Item1) + .ToArray(); + } + + private bool IsWordChar(char c) + { + return char.IsLetter(c) || c == '-' || c == '\''; + } + + private bool IsWordStart(string text, int index) + { + if (!IsWordChar(text[index])) return false; + if (index == 0) return true; + if (char.IsDigit(text[index - 1])) return false; + return !IsWordChar(text[index - 1]); + } + } +} \ No newline at end of file diff --git a/Lab9/Blue/Task4.cs b/Lab9/Blue/Task4.cs new file mode 100644 index 0000000..58cffbd --- /dev/null +++ b/Lab9/Blue/Task4.cs @@ -0,0 +1,38 @@ +namespace Lab9.Blue; + +public class Task4 : Blue +{ + public Task4(string input) : base(input) {} + + public int Output { get; private set; } + + public override string ToString() + { + return Output.ToString(); + } + + public override void Review() + { + if (Input == null) + { + Output = 0; + return; + } + + int sum = 0; + for (int i = 0; i < Input.Length; i++) + { + if (char.IsDigit((Input[i]))) + { + int number = 0; + while (i < Input.Length && char.IsDigit(Input[i])) + { + number = number * 10 + (Input[i++] - '0'); + } + sum += number; + } + } + + Output = sum; + } +} \ No newline at end of file diff --git a/Lab9Test/Blue/Task1.cs b/Lab9Test/Blue/Task1.cs index 3fd93a9..b5d8043 100644 --- a/Lab9Test/Blue/Task1.cs +++ b/Lab9Test/Blue/Task1.cs @@ -1,166 +1,166 @@ -//using System.Text.Json; - -//namespace Lab9Test.Blue -//{ -// [TestClass] -// public sealed class Task1 -// { -// private Lab9.Blue.Task1 _student; - -// private string[] _input; -// private string[][] _output; - -// [TestInitialize] -// public void LoadData() -// { -// var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; -// var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); - -// var json = JsonSerializer.Deserialize( -// File.ReadAllText(file)); - -// _input = json.GetProperty("Blue1") -// .GetProperty("input") -// .Deserialize(); - -// _output = json.GetProperty("Blue1") -// .GetProperty("output") -// .Deserialize(); -// } - -// [TestMethod] -// public void Test_00_OOP() -// { -// var type = typeof(Lab9.Blue.Task1); - -// Assert.IsTrue(type.IsClass, "Task1 must be a class"); -// Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), -// "Task1 must inherit from Blue"); - -// Assert.IsNotNull( -// type.GetConstructor(new[] { typeof(string) }), -// "Task1 must have constructor Task1(string input)" -// ); - -// Assert.IsNotNull(type.GetMethod("Review"), -// "Method Review() not found"); - -// Assert.IsNotNull(type.GetMethod("ToString"), -// "Method ToString() not found"); -// } - -// [TestMethod] -// public void Test_01_Input() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// Assert.AreEqual(_input[i], _student.Input, -// $"Input stored incorrectly\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_02_Output() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var expected = _output[i]; -// var actual = _student.Output; - -// Assert.AreEqual(expected.Length, actual.Length, -// $"Length mismatch\nTest: {i}:\n{string.Join(Environment.NewLine, actual)}"); - -// for (int j = 0; j < expected.Length; j++) -// { -// Assert.AreEqual(expected[j], actual[j], -// $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[j]}\nActual: {actual[j]}"); -// } -// } -// } - -// [TestMethod] -// public void Test_03_ToString() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var expected = string.Join(Environment.NewLine, _output[i]); -// var actual = _student.ToString(); - -// Assert.AreEqual(expected, actual, -// $"ToString output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_04_ChangeText() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var originalOutput = _student.Output; - -// var newText = _input[(i + 1) % _input.Length]; -// _student.ChangeText(newText); - -// Assert.AreEqual(newText, _student.Input, -// $"ChangeText failed\nTest: {i}"); - -// Assert.IsFalse(originalOutput.SequenceEqual(_student.Output), -// $"Output not updated\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_05_TypeSafety() -// { -// Init(0); -// _student.Review(); - -// Assert.IsInstanceOfType(_student.Output, typeof(string[]), -// $"Output must be string[]\nActual: {_student.Output.GetType()}"); -// } -// [TestMethod] -// public void Test_06_ToStringLength() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var expectedLength = string.Join(Environment.NewLine, _output[i]).Length; -// var actualLength = _student.ToString().Length; - -// Assert.AreEqual(expectedLength, actualLength, -// $"Wrong ToString length\nTest: {i}"); -// } -// } -// [TestMethod] -// public void Test_07_Inheritance() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); - -// Assert.IsTrue(_student is Lab9.Blue.Blue, -// $"Task1 must inherit from Blue\nTest: {i}"); - -// Assert.AreEqual(_input[i], _student.Input, -// $"Input mismatch\nTest: {i}"); -// } -// } - -// private void Init(int i) -// { -// _student = new Lab9.Blue.Task1(_input[i]); -// } -// } -//} \ No newline at end of file +using System.Text.Json; + +namespace Lab9Test.Blue +{ + [TestClass] + public sealed class Task1 + { + private Lab9.Blue.Task1 _student; + + private string[] _input; + private string[][] _output; + + [TestInitialize] + public void LoadData() + { + var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; + var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); + + var json = JsonSerializer.Deserialize( + File.ReadAllText(file)); + + _input = json.GetProperty("Blue1") + .GetProperty("input") + .Deserialize(); + + _output = json.GetProperty("Blue1") + .GetProperty("output") + .Deserialize(); + } + + [TestMethod] + public void Test_00_OOP() + { + var type = typeof(Lab9.Blue.Task1); + + Assert.IsTrue(type.IsClass, "Task1 must be a class"); + Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), + "Task1 must inherit from Blue"); + + Assert.IsNotNull( + type.GetConstructor(new[] { typeof(string) }), + "Task1 must have constructor Task1(string input)" + ); + + Assert.IsNotNull(type.GetMethod("Review"), + "Method Review() not found"); + + Assert.IsNotNull(type.GetMethod("ToString"), + "Method ToString() not found"); + } + + [TestMethod] + public void Test_01_Input() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + Assert.AreEqual(_input[i], _student.Input, + $"Input stored incorrectly\nTest: {i}"); + } + } + + [TestMethod] + public void Test_02_Output() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var expected = _output[i]; + var actual = _student.Output; + + Assert.AreEqual(expected.Length, actual.Length, + $"Length mismatch\nTest: {i}:\n{string.Join(Environment.NewLine, actual)}"); + + for (int j = 0; j < expected.Length; j++) + { + Assert.AreEqual(expected[j], actual[j], + $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[j]}\nActual: {actual[j]}"); + } + } + } + + [TestMethod] + public void Test_03_ToString() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var expected = string.Join(Environment.NewLine, _output[i]); + var actual = _student.ToString(); + + Assert.AreEqual(expected, actual, + $"ToString output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_04_ChangeText() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var originalOutput = _student.Output; + + var newText = _input[(i + 1) % _input.Length]; + _student.ChangeText(newText); + + Assert.AreEqual(newText, _student.Input, + $"ChangeText failed\nTest: {i}"); + + Assert.IsFalse(originalOutput.SequenceEqual(_student.Output), + $"Output not updated\nTest: {i}"); + } + } + + [TestMethod] + public void Test_05_TypeSafety() + { + Init(0); + _student.Review(); + + Assert.IsInstanceOfType(_student.Output, typeof(string[]), + $"Output must be string[]\nActual: {_student.Output.GetType()}"); + } + [TestMethod] + public void Test_06_ToStringLength() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var expectedLength = string.Join(Environment.NewLine, _output[i]).Length; + var actualLength = _student.ToString().Length; + + Assert.AreEqual(expectedLength, actualLength, + $"Wrong ToString length\nTest: {i}"); + } + } + [TestMethod] + public void Test_07_Inheritance() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + + Assert.IsTrue(_student is Lab9.Blue.Blue, + $"Task1 must inherit from Blue\nTest: {i}"); + + Assert.AreEqual(_input[i], _student.Input, + $"Input mismatch\nTest: {i}"); + } + } + + private void Init(int i) + { + _student = new Lab9.Blue.Task1(_input[i]); + } + } +} \ No newline at end of file diff --git a/Lab9Test/Blue/Task2.cs b/Lab9Test/Blue/Task2.cs index 22f53fc..afa0a34 100644 --- a/Lab9Test/Blue/Task2.cs +++ b/Lab9Test/Blue/Task2.cs @@ -1,157 +1,157 @@  -//using System; -//using System.IO; -//using System.Text.Json; -//using Microsoft.VisualStudio.TestTools.UnitTesting; - -//namespace Lab9Test.Blue -//{ -// [TestClass] -// public sealed class Task2 -// { -// private Lab9.Blue.Task2 _student; - -// private string[] _inputText; -// private string[] _inputSequence; -// private string[] _output; - -// [TestInitialize] -// public void LoadData() -// { -// var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; -// var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); - -// var json = JsonSerializer.Deserialize( -// File.ReadAllText(file)); - -// _inputText = json.GetProperty("Blue2") -// .GetProperty("inputText") -// .Deserialize(); - -// _inputSequence = json.GetProperty("Blue2") -// .GetProperty("inputSequence") -// .Deserialize(); - -// _output = json.GetProperty("Blue2") -// .GetProperty("output") -// .Deserialize(); -// } - -// [TestMethod] -// public void Test_00_OOP() -// { -// var type = typeof(Lab9.Blue.Task2); - -// Assert.IsTrue(type.IsClass, "Task2 must be a class"); -// Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), -// "Task2 must inherit from Blue"); - -// Assert.IsNotNull( -// type.GetConstructor(new[] { typeof(string), typeof(string) }), -// "Task2 must have constructor Task2(string inputText, string sequence)" -// ); - -// Assert.IsNotNull(type.GetMethod("Review"), -// "Method Review() not found"); - -// Assert.IsNotNull(type.GetMethod("ToString"), -// "Method ToString() not found"); -// } - -// [TestMethod] -// public void Test_01_Input() -// { -// for (int i = 0; i < _inputText.Length; i++) -// { -// Init(i); - -// Assert.AreEqual(_inputText[i], _student.Input, -// $"Input stored incorrectly\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_02_Output() -// { -// for (int i = 0; i < _inputText.Length; i++) -// { -// Init(i); - -// _student.Review(); - -// var expected = _output[i]; -// var actual = _student.Output; - -// Assert.AreEqual(expected, actual, -// $"Output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_03_ToString() -// { -// for (int i = 0; i < _inputText.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var expected = _output[i]; -// var actual = _student.ToString(); - -// Assert.AreEqual(expected, actual, -// $"ToString output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_04_ChangeText() -// { -// for (int i = 0; i < _inputText.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var originalOutput = _student.Output; - -// var newText = _inputText[(i + 1) % _inputText.Length]; -// _student.ChangeText(newText); - -// Assert.AreEqual(newText, _student.Input, -// $"ChangeText failed\nTest: {i}"); - -// Assert.AreNotEqual(originalOutput, _student.Output, -// $"Output not updated after ChangeText\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_05_TypeSafety() -// { -// Init(0); -// _student.Review(); - -// Assert.IsInstanceOfType(_student.Output, typeof(string), -// $"Output must be string\nActual: {_student.Output.GetType()}"); -// } - -// [TestMethod] -// public void Test_06_Inheritance() -// { -// for (int i = 0; i < _inputText.Length; i++) -// { -// Init(i); - -// Assert.IsTrue(_student is Lab9.Blue.Blue, -// $"Task2 must inherit from Blue\nTest: {i}"); - -// Assert.AreEqual(_inputText[i], _student.Input, -// $"Input mismatch\nTest: {i}"); -// } -// } - -// private void Init(int i) -// { -// _student = new Lab9.Blue.Task2(_inputText[i], _inputSequence[i]); -// } -// } -//} \ No newline at end of file +using System; +using System.IO; +using System.Text.Json; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Lab9Test.Blue +{ + [TestClass] + public sealed class Task2 + { + private Lab9.Blue.Task2 _student; + + private string[] _inputText; + private string[] _inputSequence; + private string[] _output; + + [TestInitialize] + public void LoadData() + { + var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; + var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); + + var json = JsonSerializer.Deserialize( + File.ReadAllText(file)); + + _inputText = json.GetProperty("Blue2") + .GetProperty("inputText") + .Deserialize(); + + _inputSequence = json.GetProperty("Blue2") + .GetProperty("inputSequence") + .Deserialize(); + + _output = json.GetProperty("Blue2") + .GetProperty("output") + .Deserialize(); + } + + [TestMethod] + public void Test_00_OOP() + { + var type = typeof(Lab9.Blue.Task2); + + Assert.IsTrue(type.IsClass, "Task2 must be a class"); + Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), + "Task2 must inherit from Blue"); + + Assert.IsNotNull( + type.GetConstructor(new[] { typeof(string), typeof(string) }), + "Task2 must have constructor Task2(string inputText, string sequence)" + ); + + Assert.IsNotNull(type.GetMethod("Review"), + "Method Review() not found"); + + Assert.IsNotNull(type.GetMethod("ToString"), + "Method ToString() not found"); + } + + [TestMethod] + public void Test_01_Input() + { + for (int i = 0; i < _inputText.Length; i++) + { + Init(i); + + Assert.AreEqual(_inputText[i], _student.Input, + $"Input stored incorrectly\nTest: {i}"); + } + } + + [TestMethod] + public void Test_02_Output() + { + for (int i = 0; i < _inputText.Length; i++) + { + Init(i); + + _student.Review(); + + var expected = _output[i]; + var actual = _student.Output; + + Assert.AreEqual(expected, actual, + $"Output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_03_ToString() + { + for (int i = 0; i < _inputText.Length; i++) + { + Init(i); + _student.Review(); + + var expected = _output[i]; + var actual = _student.ToString(); + + Assert.AreEqual(expected, actual, + $"ToString output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_04_ChangeText() + { + for (int i = 0; i < _inputText.Length; i++) + { + Init(i); + _student.Review(); + + var originalOutput = _student.Output; + + var newText = _inputText[(i + 1) % _inputText.Length]; + _student.ChangeText(newText); + + Assert.AreEqual(newText, _student.Input, + $"ChangeText failed\nTest: {i}"); + + Assert.AreNotEqual(originalOutput, _student.Output, + $"Output not updated after ChangeText\nTest: {i}"); + } + } + + [TestMethod] + public void Test_05_TypeSafety() + { + Init(0); + _student.Review(); + + Assert.IsInstanceOfType(_student.Output, typeof(string), + $"Output must be string\nActual: {_student.Output.GetType()}"); + } + + [TestMethod] + public void Test_06_Inheritance() + { + for (int i = 0; i < _inputText.Length; i++) + { + Init(i); + + Assert.IsTrue(_student is Lab9.Blue.Blue, + $"Task2 must inherit from Blue\nTest: {i}"); + + Assert.AreEqual(_inputText[i], _student.Input, + $"Input mismatch\nTest: {i}"); + } + } + + private void Init(int i) + { + _student = new Lab9.Blue.Task2(_inputText[i], _inputSequence[i]); + } + } +} \ No newline at end of file diff --git a/Lab9Test/Blue/Task3.cs b/Lab9Test/Blue/Task3.cs index fee60e7..4594864 100644 --- a/Lab9Test/Blue/Task3.cs +++ b/Lab9Test/Blue/Task3.cs @@ -1,165 +1,165 @@  -//using System; -//using System.IO; -//using System.Text.Json; -//using Microsoft.VisualStudio.TestTools.UnitTesting; -//using System.Linq; -//using System.Globalization; - -//namespace Lab9Test.Blue -//{ -// [TestClass] -// public sealed class Task3 -// { -// private Lab9.Blue.Task3 _student; - -// private string[] _input; -// private string[][] _output; - -// [TestInitialize] -// public void LoadData() -// { -// var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; -// var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); - -// var json = JsonSerializer.Deserialize( -// File.ReadAllText(file)); - -// _input = json.GetProperty("Blue3") -// .GetProperty("input") -// .Deserialize(); - -// _output = json.GetProperty("Blue3") -// .GetProperty("output") -// .Deserialize(); -// } - -// [TestMethod] -// public void Test_00_OOP() -// { -// var type = typeof(Lab9.Blue.Task3); - -// Assert.IsTrue(type.IsClass, "Task3 must be a class"); -// Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), -// "Task3 must inherit from Blue"); - -// Assert.IsNotNull( -// type.GetConstructor(new[] { typeof(string) }), -// "Task3 must have constructor Task3(string input)" -// ); - -// Assert.IsNotNull(type.GetMethod("Review"), -// "Method Review() not found"); - -// Assert.IsNotNull(type.GetMethod("ToString"), -// "Method ToString() not found"); -// } - -// [TestMethod] -// public void Test_01_Input() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); - -// Assert.AreEqual(_input[i], _student.Input, -// $"Input stored incorrectly\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_02_Output() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var expectedLines = _output[i]; -// var actualTuples = _student.Output; - -// Assert.AreEqual(expectedLines.Length, actualTuples.Length, -// $"Output length mismatch\nTest: {i}\n{string.Join(" ", expectedLines)}\n{string.Join(" ", actualTuples.Select(t => t.Item1))}"); - -// for (int j = 0; j < expectedLines.Length; j++) -// { -// var expected = expectedLines[j].Split(':'); - -// Assert.AreEqual(expected[0][0], actualTuples[j].Item1, -// $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[0][0]}\nActual: {actualTuples[j].Item1}"); - - -// Assert.AreEqual(double.Parse(expected[1], CultureInfo.InvariantCulture), actualTuples[j].Item2, 0.001, -// $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[1]}\nActual: {actualTuples[j].Item2}"); -// } -// } -// } - -// [TestMethod] -// public void Test_03_ToString() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// string expected = string.Join(Environment.NewLine, _output[i]); -// string actual = _student.ToString(); - -// Assert.AreEqual(expected, actual.Replace(',', '.'), true, CultureInfo.InvariantCulture, -// $"ToString output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_04_ChangeText() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var originalOutput = _student.Output; - -// var newText = _input[(i + 1) % _input.Length]; -// _student.ChangeText(newText); - -// Assert.AreEqual(newText, _student.Input, -// $"ChangeText failed\nTest: {i}"); - -// Assert.IsFalse(originalOutput.SequenceEqual(_student.Output), -// $"Output not updated after ChangeText\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_05_TypeSafety() -// { -// Init(0); -// _student.Review(); - -// Assert.IsInstanceOfType(_student.Output, typeof((char, double)[]), -// $"Output must be (char,double)[]\nActual: {_student.Output.GetType()}"); -// } - -// [TestMethod] -// public void Test_06_Inheritance() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); - -// Assert.IsTrue(_student is Lab9.Blue.Blue, -// $"Task3 must inherit from Blue\nTest: {i}"); - -// Assert.AreEqual(_input[i], _student.Input, -// $"Input mismatch\nTest: {i}"); -// } -// } - -// private void Init(int i) -// { -// _student = new Lab9.Blue.Task3(_input[i]); -// } -// } -//} \ No newline at end of file +using System; +using System.IO; +using System.Text.Json; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; +using System.Globalization; + +namespace Lab9Test.Blue +{ + [TestClass] + public sealed class Task3 + { + private Lab9.Blue.Task3 _student; + + private string[] _input; + private string[][] _output; + + [TestInitialize] + public void LoadData() + { + var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; + var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); + + var json = JsonSerializer.Deserialize( + File.ReadAllText(file)); + + _input = json.GetProperty("Blue3") + .GetProperty("input") + .Deserialize(); + + _output = json.GetProperty("Blue3") + .GetProperty("output") + .Deserialize(); + } + + [TestMethod] + public void Test_00_OOP() + { + var type = typeof(Lab9.Blue.Task3); + + Assert.IsTrue(type.IsClass, "Task3 must be a class"); + Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), + "Task3 must inherit from Blue"); + + Assert.IsNotNull( + type.GetConstructor(new[] { typeof(string) }), + "Task3 must have constructor Task3(string input)" + ); + + Assert.IsNotNull(type.GetMethod("Review"), + "Method Review() not found"); + + Assert.IsNotNull(type.GetMethod("ToString"), + "Method ToString() not found"); + } + + [TestMethod] + public void Test_01_Input() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + + Assert.AreEqual(_input[i], _student.Input, + $"Input stored incorrectly\nTest: {i}"); + } + } + + [TestMethod] + public void Test_02_Output() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var expectedLines = _output[i]; + var actualTuples = _student.Output; + + Assert.AreEqual(expectedLines.Length, actualTuples.Length, + $"Output length mismatch\nTest: {i}\n{string.Join(" ", expectedLines)}\n{string.Join(" ", actualTuples.Select(t => t.Item1))}"); + + for (int j = 0; j < expectedLines.Length; j++) + { + var expected = expectedLines[j].Split(':'); + + Assert.AreEqual(expected[0][0], actualTuples[j].Item1, + $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[0][0]}\nActual: {actualTuples[j].Item1}"); + + + Assert.AreEqual(double.Parse(expected[1], CultureInfo.InvariantCulture), actualTuples[j].Item2, 0.001, + $"Line mismatch\nTest: {i}, Index: {j}\nExpected: {expected[1]}\nActual: {actualTuples[j].Item2}"); + } + } + } + + [TestMethod] + public void Test_03_ToString() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + string expected = string.Join(Environment.NewLine, _output[i]); + string actual = _student.ToString(); + + Assert.AreEqual(expected, actual.Replace(',', '.'), true, CultureInfo.InvariantCulture, + $"ToString output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_04_ChangeText() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var originalOutput = _student.Output; + + var newText = _input[(i + 1) % _input.Length]; + _student.ChangeText(newText); + + Assert.AreEqual(newText, _student.Input, + $"ChangeText failed\nTest: {i}"); + + Assert.IsFalse(originalOutput.SequenceEqual(_student.Output), + $"Output not updated after ChangeText\nTest: {i}"); + } + } + + [TestMethod] + public void Test_05_TypeSafety() + { + Init(0); + _student.Review(); + + Assert.IsInstanceOfType(_student.Output, typeof((char, double)[]), + $"Output must be (char,double)[]\nActual: {_student.Output.GetType()}"); + } + + [TestMethod] + public void Test_06_Inheritance() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + + Assert.IsTrue(_student is Lab9.Blue.Blue, + $"Task3 must inherit from Blue\nTest: {i}"); + + Assert.AreEqual(_input[i], _student.Input, + $"Input mismatch\nTest: {i}"); + } + } + + private void Init(int i) + { + _student = new Lab9.Blue.Task3(_input[i]); + } + } +} \ No newline at end of file diff --git a/Lab9Test/Blue/Task4.cs b/Lab9Test/Blue/Task4.cs index 52ad58e..8f1932a 100644 --- a/Lab9Test/Blue/Task4.cs +++ b/Lab9Test/Blue/Task4.cs @@ -1,149 +1,149 @@  -//using System; -//using System.IO; -//using System.Text.Json; -//using Microsoft.VisualStudio.TestTools.UnitTesting; -//using System.Linq; - -//namespace Lab9Test.Blue -//{ -// [TestClass] -// public sealed class Task4 -// { -// private Lab9.Blue.Task4 _student; - -// private string[] _input; -// private int[] _output; - -// [TestInitialize] -// public void LoadData() -// { -// var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; -// var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); - -// var json = JsonSerializer.Deserialize( -// File.ReadAllText(file)); - -// _input = json.GetProperty("Blue4") -// .GetProperty("input") -// .Deserialize(); - -// _output = json.GetProperty("Blue4") -// .GetProperty("output") -// .Deserialize(); -// } - -// [TestMethod] -// public void Test_00_OOP() -// { -// var type = typeof(Lab9.Blue.Task4); - -// Assert.IsTrue(type.IsClass, "Task4 must be a class"); -// Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), -// "Task4 must inherit from Blue"); - -// Assert.IsNotNull( -// type.GetConstructor(new[] { typeof(string) }), -// "Task4 must have constructor Task4(string input)" -// ); - -// Assert.IsNotNull(type.GetMethod("Review"), -// "Method Review() not found"); - -// Assert.IsNotNull(type.GetMethod("ToString"), -// "Method ToString() not found"); -// } - -// [TestMethod] -// public void Test_01_Input() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); - -// Assert.AreEqual(_input[i], _student.Input, -// $"Input stored incorrectly\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_02_Output() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// Assert.AreEqual(_output[i], _student.Output, -// $"Output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_03_ToString() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// string expected = _output[i].ToString(); -// string actual = _student.ToString(); - -// Assert.AreEqual(expected, actual, -// $"ToString output mismatch\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_04_ChangeText() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); -// _student.Review(); - -// var originalOutput = 666; - -// var newText = "Проверим 600 + 60 + 6"; -// _student.ChangeText(newText); - -// Assert.AreEqual(newText, _student.Input, -// $"ChangeText failed\nTest: {i}"); - -// Assert.AreEqual(originalOutput, _student.Output, -// $"Output not updated after ChangeText\nTest: {i}"); -// } -// } - -// [TestMethod] -// public void Test_05_TypeSafety() -// { -// Init(0); -// _student.Review(); - -// Assert.IsInstanceOfType(_student.Output, typeof(int), -// $"Output must be int\nActual: {_student.Output.GetType()}"); -// } - -// [TestMethod] -// public void Test_06_Inheritance() -// { -// for (int i = 0; i < _input.Length; i++) -// { -// Init(i); - -// Assert.IsTrue(_student is Lab9.Blue.Blue, -// $"Task4 must inherit from Blue\nTest: {i}"); - -// Assert.AreEqual(_input[i], _student.Input, -// $"Input mismatch\nTest: {i}"); -// } -// } - -// private void Init(int i) -// { -// _student = new Lab9.Blue.Task4(_input[i]); -// } -// } -//} \ No newline at end of file +using System; +using System.IO; +using System.Text.Json; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; + +namespace Lab9Test.Blue +{ + [TestClass] + public sealed class Task4 + { + private Lab9.Blue.Task4 _student; + + private string[] _input; + private int[] _output; + + [TestInitialize] + public void LoadData() + { + var folder = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; + var file = Path.Combine(folder, "Lab9Test", "Blue", "data.json"); + + var json = JsonSerializer.Deserialize( + File.ReadAllText(file)); + + _input = json.GetProperty("Blue4") + .GetProperty("input") + .Deserialize(); + + _output = json.GetProperty("Blue4") + .GetProperty("output") + .Deserialize(); + } + + [TestMethod] + public void Test_00_OOP() + { + var type = typeof(Lab9.Blue.Task4); + + Assert.IsTrue(type.IsClass, "Task4 must be a class"); + Assert.IsTrue(type.IsSubclassOf(typeof(Lab9.Blue.Blue)), + "Task4 must inherit from Blue"); + + Assert.IsNotNull( + type.GetConstructor(new[] { typeof(string) }), + "Task4 must have constructor Task4(string input)" + ); + + Assert.IsNotNull(type.GetMethod("Review"), + "Method Review() not found"); + + Assert.IsNotNull(type.GetMethod("ToString"), + "Method ToString() not found"); + } + + [TestMethod] + public void Test_01_Input() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + + Assert.AreEqual(_input[i], _student.Input, + $"Input stored incorrectly\nTest: {i}"); + } + } + + [TestMethod] + public void Test_02_Output() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + Assert.AreEqual(_output[i], _student.Output, + $"Output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_03_ToString() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + string expected = _output[i].ToString(); + string actual = _student.ToString(); + + Assert.AreEqual(expected, actual, + $"ToString output mismatch\nTest: {i}"); + } + } + + [TestMethod] + public void Test_04_ChangeText() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + _student.Review(); + + var originalOutput = 666; + + var newText = "Проверим 600 + 60 + 6"; + _student.ChangeText(newText); + + Assert.AreEqual(newText, _student.Input, + $"ChangeText failed\nTest: {i}"); + + Assert.AreEqual(originalOutput, _student.Output, + $"Output not updated after ChangeText\nTest: {i}"); + } + } + + [TestMethod] + public void Test_05_TypeSafety() + { + Init(0); + _student.Review(); + + Assert.IsInstanceOfType(_student.Output, typeof(int), + $"Output must be int\nActual: {_student.Output.GetType()}"); + } + + [TestMethod] + public void Test_06_Inheritance() + { + for (int i = 0; i < _input.Length; i++) + { + Init(i); + + Assert.IsTrue(_student is Lab9.Blue.Blue, + $"Task4 must inherit from Blue\nTest: {i}"); + + Assert.AreEqual(_input[i], _student.Input, + $"Input mismatch\nTest: {i}"); + } + } + + private void Init(int i) + { + _student = new Lab9.Blue.Task4(_input[i]); + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..ce12b8d --- /dev/null +++ b/Program.cs @@ -0,0 +1,159 @@ +using System.Text; +using System.Text.RegularExpressions; + +namespace indexers; + +class Program +{ + static void Main(string[] args) + { + var students = new Student[] + { + new Student("A", "a", new int[,] { { 1, 2, 3 }, { 5, 5, 5 } }), + new Student("B", "b", new int[,] { { 1, 2, 1 }, { 3, 2, 2 } }), + new Student("C", "c", new int[,] { { 4, 3, 4 }, { 4, 5, 5 } }) + }; + // foreach (var s in students) + // { + // Console.WriteLine(s[0,1]); + // } + + string str = "I am a good student!"; + string str2 = "Not! A am!"; + str = "Not! I am!"; + str2 = str; + Console.WriteLine(str2); + //str2 = str.Replace("am", "you"); + //str2 = str.Replace("c", "a"); + //str2 = str.Substring(4,3); + // int a = str.IndexOf('a'); + // Console.WriteLine(a); + var strings = str.Split(new char[] { '.', '?', '!' }, StringSplitOptions.RemoveEmptyEntries); + Console.WriteLine(str2); + + foreach (var c in "В 9-й работе разрешены методы следующих классов: Console, Math, Random, Array, Linq.") + { + bool isLetter = Char.IsLetter(c); + bool isDigit = Char.IsDigit(c); + bool isSpaceTabNewLine = Char.IsSeparator(c); + bool isPunctuation = Char.IsPunctuation(c); + } + + string output = $"New\ntext\n\ron\r\neach{Environment.NewLine}line!"; + + Console.WriteLine(str2); + + StringBuilder sb = new StringBuilder(); + sb.Append("fsfs"); + sb.Remove(1, 5); + // преобразование динамического массива символов в строку + sb.ToString(); + + //изучить regex + + // Regex regex = new Regex("[/d+]"); + // var result = regex.Match( + // "В 9-й работе разрешены методы следующих классов: " + + // "Console, Math, Random, Array, Linq."); + // foreach (var match in result.Value) + // { + // Console.WriteLine(match); + // } + } + +} + +public class Student +{ + private string _name; + private string _surname; + private int[,] _marks; + private double[] _averageMarks; + + public char this[int idx] + { + get + { + return _name[idx]; + } + } + public int[,] Marks => (int[,]) _marks.Clone(); + public double[] AverageMarks + { + get + { + if (_marks == null || _marks.GetLength(0) == 0 || _marks.GetLength(1) == 0) return null; + var average = new double[_marks.GetLength(0)]; + for (int i = 0; i < average.Length; i++) + { + for (int j = 0; j < average.GetLength(1); j++) + { + average[i] += (double) _marks[i, j] / _marks.GetLength(1); + } + } + return average; + } + } + + // public double this[int idx] + // { + // get + // { + // return AverageMarks[idx]; + // } + // } + + public int this[int i, int j] + { + get + { + return _marks[i, j]; + } + // set + // { + // if (value >= 2 && value <= 5) + // _marks[i, j] = value; + // } + } + + public Student(string name, string surname, int[,] marks = null) + { + _name = name; + _surname = surname; + if (marks != null) + { + _marks = (int[,])marks.Clone(); + } + } + + public override string ToString() + { + var output = _name + " " + _surname; + for (int i = 0; i < _marks.GetLength(0); i++) + { + for (int j = 0; j < _marks.GetLength(1); j++) + { + output += _marks[i, j] + " "; + } + + output = output.TrimEnd(); + output += Environment.NewLine; + } + + return output; + + StringBuilder sb = new StringBuilder(_name); + sb.Append(" "); + sb.AppendLine(_surname); + for (int i = 0; i < _marks.GetLength(0); i++) + { + for (int j = 0; j < _marks.GetLength(1); j++) + { + sb.Append(_marks[i, j]).Append(" "); + } + + sb = sb.Remove(sb.Length - 1, 1); + sb.AppendLine(); + } + } +} \ No newline at end of file