-
Notifications
You must be signed in to change notification settings - Fork 300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Попов Захар #235
Open
BlizPerfect
wants to merge
16
commits into
kontur-courses:master
Choose a base branch
from
BlizPerfect:BlizPerfect/markdown-task
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,036
−9
Open
Попов Захар #235
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
f53e022
Проведено начальное проектирование.
BlizPerfect f8768e2
В работе приложения больше не используются конвёртеры тегов.
BlizPerfect 476d331
В работе приложения больше не используются теги в явном виде.
BlizPerfect 36691f2
Реализация с помощью паттерна "Посетитель" получения визуального пред…
BlizPerfect f04e7fe
Рефакторинг токенов.
BlizPerfect a0e7f63
Реализация парсера.
BlizPerfect f99e193
Смена типа выходного файла на библиотеку.
BlizPerfect f0948eb
Написание тестов
BlizPerfect 1bfdc4a
Исправил один int в цикле на var.
BlizPerfect 058c67f
Выполнен рефакторинг тестов и изменено поведение парсера.
BlizPerfect c166721
Рефакторинг тестов в MdTests.
BlizPerfect 1835148
Рефакторинг ParserMd
BlizPerfect 7b04aad
Измнена логика работы теста по замеру алгоритмической сложности.
BlizPerfect e7e24a7
Токен теперь хранит в себе свой тип
BlizPerfect d7acd5a
Md теперь принимает конкеретный ParserMd.
BlizPerfect b176806
Рефакторинг кода
BlizPerfect File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,36 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector" Version="6.0.2"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="FluentAssertions" Version="6.12.2" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> | ||
<PackageReference Include="NUnit" Version="4.2.2" /> | ||
<PackageReference Include="NUnit.Analyzers" Version="4.4.0"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="NUnit.Console" Version="3.18.3" /> | ||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.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,208 @@ | ||
using FluentAssertions; | ||
using Markdown.Parsers.MdParsers; | ||
using Markdown.Renderers; | ||
using System.Diagnostics; | ||
|
||
namespace Markdown.Tests | ||
{ | ||
internal class MdTests | ||
{ | ||
[Test] | ||
public void Md_ThrowsException_ReceivingNullAsIParser() | ||
{ | ||
Assert.Throws<ArgumentNullException>(() => new Md(null!, new RendererHTML())); | ||
} | ||
|
||
[Test] | ||
public void Md_ThrowsException_ReceivingNullAsIRenderer() | ||
{ | ||
Assert.Throws<ArgumentNullException>(() => new Md(new ParserMd(), null!)); | ||
} | ||
|
||
[TestCase("__Bold token__", "<strong>Bold token</strong>")] | ||
[TestCase("_Italic token_", "<em>Italic token</em>")] | ||
[TestCase("# Header token", "<h1>Header token</h1>")] | ||
[TestCase("Text token", "Text token")] | ||
[TestCase("# _Set_ __of__ tokens", "<h1><em>Set</em> <strong>of</strong> tokens</h1>")] | ||
public void Md_RendersCorrectly_SimpleTokens(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase(@"\_\_Text token\_\_", "__Text token__")] | ||
[TestCase(@"\_Text token\_", "_Text token_")] | ||
[TestCase(@"\# Text token", "# Text token")] | ||
[TestCase(@"#\ Text token", "# Text token")] | ||
public void Md_RendersCorrectly_SimpleEscapedTokens(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase(@"Ste\gosaur\us", @"Ste\gosaur\us")] | ||
[TestCase(@"\", @"\")] | ||
[TestCase(@"_Italic \token_", @"<em>Italic \token</em>")] | ||
public void Md_RendersCorrectly_WhenEscapedNothing(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase(@"\\a", @"\a")] | ||
[TestCase(@"\\_\\_Text token\\_\\_", @"\<em>\</em>Text token\<em>\</em>")] | ||
[TestCase(@"\\_Italic token\\_", @"\<em>Italic token\</em>")] | ||
public void Md_RendersCorrectly_WhenEscapeEscaped(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("__Outer bold _Inner italic part_ outer bold__", "<strong>Outer bold <em>Inner italic part</em> outer bold</strong>")] | ||
public void Md_RendersCorrectly_ItalicInsideBold(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("_Outer italic __Inner Bold part__ outer Italic_", "<em>Outer italic __Inner Bold part__ outer Italic</em>")] | ||
public void Md_RendersCorrectly_BoldInsideItalic(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("_Digits 12 3_", "<em>Digits 12 3</em>")] | ||
[TestCase("Digits_12_3", "Digits_12_3")] | ||
[TestCase("Digits__12__3", "Digits__12__3")] | ||
public void Md_RendersCorrectly_DigitsWithUnderscores(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
|
||
[TestCase("__Sta__rt", "<strong>Sta</strong>rt")] | ||
[TestCase("_Sta_rt", "<em>Sta</em>rt")] | ||
[TestCase("S__tar__t", "S<strong>tar</strong>t")] | ||
[TestCase("S_tar_t", "S<em>tar</em>t")] | ||
[TestCase("St__art__", "St<strong>art</strong>")] | ||
[TestCase("St_art_", "St<em>art</em>")] | ||
public void Md_RendersCorrectly_WordsWithUnderscores(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("Hel_lo, Wor_ld", "Hel_lo, Wor_ld")] | ||
[TestCase("Hel__lo, Wor__ld", "Hel__lo, Wor__ld")] | ||
public void Md_RendersCorrectly_UnderscoresInsideDifferentWords(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("_Hello world__", "_Hello world__")] | ||
[TestCase("__Hello world_", "__Hello world_")] | ||
public void Md_RendersCorrectly_UnpairedTags(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("_ Hello world_", "_ Hello world_")] | ||
[TestCase("_ Hello world _", "_ Hello world _")] | ||
[TestCase("_Hello world _", "_Hello world _")] | ||
[TestCase("__ Hello world__", "__ Hello world__")] | ||
[TestCase("__ Hello world __", "__ Hello world __")] | ||
[TestCase("__Hello world __", "__Hello world __")] | ||
public void Md_RendersCorrectly_WithSpaceAfterOrBeforeTag(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("_Hello__ _world__", "_Hello__ _world__")] | ||
[TestCase("__Hello_ __world_", "__Hello_ __world_")] | ||
public void Md_RendersCorrectly_WithUnderscoreIntersections(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("__", "__")] | ||
[TestCase("____", "____")] | ||
public void Md_RendersCorrectly_UnderscoresWithEmptyValue(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase("# Header token 1\n# Header token 2", "<h1>Header token 1</h1><h1>Header token 2</h1>")] | ||
[TestCase("this is regular sentence # 123", "this is regular sentence # 123")] | ||
public void Md_RendersCorrectly_Heading(string input, string expected) | ||
{ | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
var actual = md.Render(input); | ||
actual.Should().Be(expected); | ||
} | ||
|
||
[TestCase(5, 10, 0.5)] | ||
public void Md_ShouldWorkInLinearTime(int iterations, int baseIterationSize, double measurementError) | ||
{ | ||
var testSizes = new int[iterations]; | ||
testSizes[0] = baseIterationSize; | ||
for (var i = 1; i < iterations; i++) | ||
{ | ||
testSizes[i] = 2 * testSizes[i - 1]; | ||
} | ||
|
||
var executionTimes = GetExecutionTimes(testSizes); | ||
|
||
for (var i = 1; i < iterations; i++) | ||
{ | ||
var growthFactor = executionTimes[i] / executionTimes[i - 1]; | ||
Assert.That(growthFactor, Is.LessThanOrEqualTo(2.0 + measurementError)); | ||
} | ||
} | ||
|
||
private double[] GetExecutionTimes(int[] sizes) | ||
{ | ||
var results = new double[sizes.Length]; | ||
var md = new Md(new ParserMd(), new RendererHTML()); | ||
md.Render(GenerateText(sizes[^1])); | ||
|
||
for (var i = 0; i < sizes.Length; i++) | ||
{ | ||
md = new Md(new ParserMd(), new RendererHTML()); | ||
var text = GenerateText(sizes[i]); | ||
|
||
var stopwatch = Stopwatch.StartNew(); | ||
md.Render(text); | ||
stopwatch.Stop(); | ||
|
||
results[i] = stopwatch.Elapsed.TotalMilliseconds; | ||
} | ||
|
||
return results; | ||
} | ||
|
||
private string GenerateText(int numberOfRepetitions) | ||
=> string.Concat( | ||
Enumerable.Repeat(@"__This _is_ a__ simple text \_for\_ crea\ting complex _test_ __text__.", | ||
numberOfRepetitions)); | ||
} | ||
} |
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,77 @@ | ||
using FluentAssertions; | ||
using Markdown.Parsers.MdParsers; | ||
using Markdown.Tokens.HtmlTokens; | ||
|
||
namespace Markdown.Tests.ParsersTests | ||
{ | ||
[TestFixture] | ||
public class ParserMdTests | ||
BlizPerfect marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
private ParserMd _parser; | ||
private readonly List<IRenderable> _expected = new List<IRenderable>(); | ||
|
||
[SetUp] | ||
public void SetUp() | ||
{ | ||
_parser = new ParserMd(); | ||
_expected.Clear(); | ||
} | ||
|
||
[TestCase("__Bold token__")] | ||
public void Parse_SimpleBoldText_Correctly(string text) | ||
{ | ||
_expected.Add( | ||
new BoldToken( | ||
new TextToken("Bold token"))); | ||
CheckCorrectness(text); | ||
} | ||
BlizPerfect marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
[TestCase("# Header token")] | ||
public void Parse_SimpleHeaderText_Correctly(string text) | ||
{ | ||
_expected.Add( | ||
new HeaderToken( | ||
new TextToken("Header token"))); | ||
CheckCorrectness(text); | ||
} | ||
|
||
[TestCase("_Italic token_")] | ||
public void Parse_SimpleItalicText_Correctly(string text) | ||
{ | ||
_expected.Add( | ||
new ItalicToken( | ||
new TextToken("Italic token"))); | ||
CheckCorrectness(text); | ||
} | ||
|
||
[TestCase("Text Token")] | ||
public void Parse_SimpleText_Correctly(string text) | ||
{ | ||
_expected.Add( | ||
new TextToken(text)); | ||
CheckCorrectness(text); | ||
} | ||
|
||
[TestCase("# _Set_ __of__ tokens")] | ||
public void Parse_ComplexText_Correctly(string text) | ||
{ | ||
_expected.Add( | ||
new HeaderToken( | ||
new SetToken( | ||
new ItalicToken( | ||
new TextToken("Set")), | ||
new TextToken(" "), | ||
new BoldToken( | ||
new TextToken("of")), | ||
new TextToken(" tokens")))); | ||
CheckCorrectness(text); | ||
} | ||
|
||
private void CheckCorrectness(string text) | ||
{ | ||
var actual = _parser.Parse(text); | ||
actual.Should().BeEquivalentTo(_expected, | ||
options => options.RespectingRuntimeTypes()); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Напишу сюда, так как теста на случай с пересечением тегов нету
Сейчас выделением считается первое попадание. Что нарушает спецификацию.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вроде проблема осталась
Тест
__Hello_ __world_
не совсем релевантен, потому что по спецификации__hello __
не может быть превращён в<strong>hello </strong>
из-за пробела.