-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
224 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. Обрати внимание: если упадет читаемость кода, то дополнительный балл засчитан не будет! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters