Skip to content

Commit

Permalink
Created test for md class
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxSaz committed Nov 24, 2024
1 parent e149587 commit 26a2a90
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 1 deletion.
37 changes: 37 additions & 0 deletions cs/MarkdownTests/Markdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Markdown

Напиши процессор упрощённого markdown-подобного языка разметки.

[Спецификация языка разметки](MarkdownSpec.md).

## Формат

В fork-е этого репозитория создай проект Markdown и реализуй метод Render класса Md. Он принимает в качестве аргумента текст в markdown-подобной разметке, и возвращает строку с html-кодом этого текста согласно спецификации.

Обрати внимание, что в этой задаче <ins>запрещено</ins> использовать регулярные выражения.

## Важные моменты
1. Проведи начальное проектирование: зафиксируй классы и их методы в коде (а также связи между классами), но не пиши внутренности методов
2. Покажи декомпозицию наставнику, получи обратную связь
3. После этого приступай к реализации методов, используя TDD
4. Помни, твой алгоритм должен работать быстро — линейно или почти линейно от размера входа. Не забудь написать такой тест!

## Оценка

#### Минимальные требования (на 1 балл)
1. Поддерживаются тэги `_`, `__` и `#` согласно спецификации
2. Тесты

#### Полное решение (на 2 балла)
1. Выполнены минимальные требования
2. Решение разбито на составные части, каждая из которых легко читается

#### Максимальное решение (на 3 балла)
1. Выполнено полное решение
2. Умеет рендериться <ins>один</ins> из дополнительных тегов:
- Маркерованный список
- Нумерованный список
- Ссылка
- Картинка
3. В файле [спецификации](MarkdownSpec.md) подробно описано, как работает новый тег
4. Обрати внимание: если упадет читаемость кода, то дополнительный балл засчитан не будет!
73 changes: 73 additions & 0 deletions cs/MarkdownTests/MarkdownSpec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Спецификация языка разметки

Посмотрите этот файл в сыром виде. Сравните с тем, что показывает github.
Все совпадения случайны ;)



# Курсив

Текст, _окруженный с двух сторон_ одинарными символами подчерка,
должен помещаться в HTML-тег \<еm> вот так:

Текст, \<еm>окруженный с двух сторон\</еm> одинарными символами подчерка,
должен помещаться в HTML-тег \<еm>.



# Полужирный

__Выделенный двумя символами текст__ должен становиться полужирным с помощью тега \<strоng>.



# Экранирование

Любой символ можно экранировать, чтобы он не считался частью разметки.
\_Вот это\_, не должно выделиться тегом \<еm>.

Символ экранирования исчезает из результата, только если экранирует что-то.
Здесь сим\волы экранирования\ \должны остаться.\

Символ экранирования тоже можно экранировать: \\_вот это будет выделено тегом_ \<еm>



# Взаимодействие тегов

Внутри __двойного выделения _одинарное_ тоже__ работает.

Но не наоборот — внутри _одинарного __двойное__ не_ работает.

Подчерки внутри текста c цифрами_12_3 не считаются выделением и должны оставаться символами подчерка.

Однако выделять часть слова они могут: и в _нач_але, и в сер_еди_не, и в кон_це._

В то же время выделение в ра_зных сл_овах не работает.

__Непарные_ символы в рамках одного абзаца не считаются выделением.

За подчерками, начинающими выделение, должен следовать непробельный символ. Иначе эти_ подчерки_ не считаются выделением
и остаются просто символами подчерка.

Подчерки, заканчивающие выделение, должны следовать за непробельным символом. Иначе эти _подчерки _не считаются_ окончанием выделения
и остаются просто символами подчерка.

В случае __пересечения _двойных__ и одинарных_ подчерков ни один из них не считается выделением.

Если внутри подчерков пустая строка ____, то они остаются символами подчерка.



# Заголовки

Абзац, начинающийся с "# ", выделяется тегом \<h1> в заголовок.
В тексте заголовка могут присутствовать все прочие символы разметки с указанными правилами.

Таким образом

# Заголовок __с _разными_ символами__

превратится в:

\<h1>Заголовок \<strоng>с \<еm>разными\</еm> символами\</strоng>\</h1>
29 changes: 29 additions & 0 deletions cs/MarkdownTests/MarkdownTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Markdown\Markdown.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>

</Project>
78 changes: 78 additions & 0 deletions cs/MarkdownTests/MdShould.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using FluentAssertions;

namespace Markdown.Tests;

[TestFixture]
public class MdShould
{
private Md _markdown = new();

[TestCase("test, _te x t_ tt", ExpectedResult = "test, <em>te x t</em> tt", TestName = "Render italic text with surrounding regular text")]
[TestCase("_be_gin", ExpectedResult = "<em>be</em>gin", TestName = "Render italic text at word start")]
[TestCase("mi_dd_le", ExpectedResult = "mi<em>dd</em>le", TestName = "Render italic text in word middle")]
[TestCase("the e_nd._", ExpectedResult = "the e<em>nd.</em>", TestName = "Render italic text at word end")]
public string RenderItalicText_ShouldParseCorrectly(string markdownText) =>
_markdown.Render(markdownText);

[TestCase("with numbers_12_3 text", ExpectedResult = "with numbers_12_3 text", TestName = "Should not parse when contains numbers")]
[TestCase("_text___", ExpectedResult = "_text___", TestName = "Should not parse with unmatched underscores")]
[TestCase("text_ text_", ExpectedResult = "text_ text_", TestName = "Should not parse with spaces after tags")]
[TestCase("_text text _text", ExpectedResult = "_text text _text", TestName = "Should not parse with space before end tag")]
[TestCase("text _text text", ExpectedResult = "text _text text", TestName = "Should not parse with only start tag")]
[TestCase("text t_ext ___te_xt", ExpectedResult = "text t_ext ___te_xt", TestName = "Should not parse with multiple underscores")]
public string RenderItalicText_ShouldNotParseInvalidCases(string markdownText) =>
_markdown.Render(markdownText);

[TestCase("__text__", ExpectedResult = "<strong>text</strong>", TestName = "Render basic bold text")]
public string RenderBoldText_ShouldParseCorrectly(string markdownText) =>
_markdown.Render(markdownText);

[TestCase(@"\_text\_", ExpectedResult = @"_text_", TestName = "Handle single escaped underscore")]
[TestCase(@"\\\_text\\\_", ExpectedResult = @"\_text\_", TestName = "Handle triple escaped underscore")]
public string RenderEscapedText_ShouldHandleEscapedUnderscores(string markdownText) =>
_markdown.Render(markdownText);

[TestCase(@"\\_text\\_", ExpectedResult = @"\<em>text\</em>", TestName = "Handle double escaped underscore")]
[TestCase(@"\\\\_text\\\\_", ExpectedResult = @"\\<em>text\\</em>", TestName = "Handle quad escaped underscore")]
public string RenderEscapedText_ShouldPreserveEscapedCharacters(string markdownText) =>
_markdown.Render(markdownText);

[TestCase("__t_t_t_t__", ExpectedResult = "<strong>t<em>t</em>t_t</strong>", TestName = "Render italic inside bold")]
[TestCase("__t_t___t__", ExpectedResult = "<strong>t_t___t</strong>", TestName = "Handle multiple underscores inside bold")]
[TestCase(@"\__t_t___t__", ExpectedResult = @"__t_t___t__", TestName = "Handle escaped bold start tag")]
[TestCase("t _t __t__ t_ t", ExpectedResult = @"t <em>t __t__ t</em> t", TestName = "Handle bold inside italic")]
[TestCase("t __t _t_ t__ t", ExpectedResult = @"t <strong>t <em>t</em> t</strong> t", TestName = "Handle nested italic in bold")]
[TestCase("t _t t __t t_ t__ t", ExpectedResult = "t _t t __t t_ t__ t", TestName = "Handle overlapping tags")]
[TestCase("__t _t t__ t t_ _t t__ t t_ t__ t", ExpectedResult = "__t _t t__ t t_ <em>t t__ t t</em> t__ t", TestName = "Handle complex tag intersections")]
[TestCase(@"Here sim\bols of shielding\ \should stay.\", ExpectedResult = @"Here sim\bols of shielding\ \should stay.\", TestName = "Preserve escaped characters")]
public string RenderMixedFormatting_ShouldHandleComplexCases(string markdownText) =>
_markdown.Render(markdownText);

[TestCase(" # text", ExpectedResult = " <h1>text</h1>", TestName = "Render header with leading spaces")]
[TestCase("# text", ExpectedResult = "<h1>text</h1>", TestName = "Render basic header")]
[TestCase("# _text_", ExpectedResult = "<h1><em>text</em></h1>", TestName = "Render header with italic text")]
[TestCase("# t __t _t_ t__", ExpectedResult = "<h1>t <strong>t <em>t</em> t</strong></h1>", TestName = "Render header with mixed formatting")]
public string RenderHeaders_ShouldParseCorrectly(string markdownText) =>
_markdown.Render(markdownText);

[TestCase("#_text_", ExpectedResult = "#<em>text</em>", TestName = "Should not parse header without space")]
public string RenderHeaders_ShouldNotParseInvalidCases(string markdownText) =>
_markdown.Render(markdownText);

[Test]
[TestCase("Markdown.md", TestName = "Convert Markdown file to HTML")]
[TestCase("MarkdownSpec.md", TestName = "Convert MarkdownSpec file to HTML")]
public void RenderMarkdownFile_ShouldCreateHtmlFile(string markdownPath)
{
var markdownContent = File.ReadAllText(markdownPath);
var htmlPath = Path.ChangeExtension(markdownPath, ".html");
File.Delete(htmlPath);

using (var htmlWriter = File.CreateText(htmlPath))
{
htmlWriter.WriteLine(_markdown.Render(markdownContent));
}

File.Exists(htmlPath).Should().BeTrue();
}
}
8 changes: 7 additions & 1 deletion cs/clean-code.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35506.116 d17.12
VisualStudioVersion = 17.12.35506.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chess", "Chess\Chess.csproj", "{DBFBE40E-EE0C-48F4-8763-EBD11C960081}"
EndProject
Expand All @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdown", "Markdown\Markdown.csproj", "{C2E421BA-68A4-42D6-92CC-57FE3FAD2E90}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarkdownTests", "MarkdownTests\MarkdownTests.csproj", "{ADFA7A5D-9F1C-47A3-B996-75D6072F39F9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -33,6 +35,10 @@ Global
{C2E421BA-68A4-42D6-92CC-57FE3FAD2E90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2E421BA-68A4-42D6-92CC-57FE3FAD2E90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2E421BA-68A4-42D6-92CC-57FE3FAD2E90}.Release|Any CPU.Build.0 = Release|Any CPU
{ADFA7A5D-9F1C-47A3-B996-75D6072F39F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADFA7A5D-9F1C-47A3-B996-75D6072F39F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADFA7A5D-9F1C-47A3-B996-75D6072F39F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADFA7A5D-9F1C-47A3-B996-75D6072F39F9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit 26a2a90

Please sign in to comment.