-
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
Мажирин Александр #237
base: master
Are you sure you want to change the base?
Мажирин Александр #237
Conversation
cs/Markdown/Markdown/Md.cs
Outdated
{ | ||
public string Render(string md) | ||
{ | ||
var tokenizer = new Tokenizer(); |
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.
Выглядит как что-то, что можно вынести в приватное поле и генерировать только при создании класса Md
cs/Markdown/Markdown/Md.cs
Outdated
{ | ||
var tokenizer = new Tokenizer(); | ||
var tokens = tokenizer.Tokenize(md); | ||
var renderer = new HtmlRenderer(); |
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.
аналогично предыдущему. Не требует специфичных данных метода и не похоже, чтобы сохранял во внутреннюю структуру что-то
cs/Markdown/Markdown.csproj
Outdated
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net9.0</TargetFramework> |
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.
net9 только вышел из беты, поэтому активно пока не применяется. Лучше по началу использовать стабильные версии с долгосрочной поддержкой. Такие как 8, например
cs/Markdown/Program.cs
Outdated
static void Main(string[] args) | ||
{ | ||
var mdFile = File.ReadAllText("Markdown.md"); | ||
var md = new Markdown.Md(); |
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.
Точно нужно указывать полное имя класса с namespace?
cs/Markdown/Program.cs
Outdated
{ | ||
var mdFile = File.ReadAllText("Markdown.md"); | ||
var md = new Markdown.Md(); | ||
Console.WriteLine(md.Render(mdFile)); |
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.
Для тестов вполне достаточно выводить в консоль. Но если делать какой-то cli, то лучше сохранять в файлик html рядом с входным
cs/Markdown/Token/IToken.cs
Outdated
@@ -0,0 +1,6 @@ | |||
namespace Markdown.Token; | |||
|
|||
public interface IToken |
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.
токен больше похож на data class, нежели что-то с различными реализациями. Расскажи, что вкладываешь в него и как планируешь использовать при парсинге?
cs/MarkdownTests/MarkdownTests.cs
Outdated
[Test] | ||
public void Render_ShouldReturnSimpleText() | ||
{ | ||
md.Render("Hello, world!").Should().Be("Hello, world!"); |
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.
Вынесем текст в константу метода? Чтобы точно не менялась )
cs/MarkdownTests/MarkdownTests.cs
Outdated
|
||
namespace MarkdownTests; | ||
|
||
public class MarkdownTests |
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.
Класс всё-таки Md, хоть под ним и подразумевается Markdown
cs/MarkdownTests/MarkdownTests.cs
Outdated
[Test] | ||
public void Render_ShouldReturnImage() | ||
{ | ||
md.Render("(Hello, image!)[img]").Should().Be("<img alt=\"Hello, image!\" src=\"img\"/>"); |
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.
Этот тег получается ты придумал сам? В md для картинок применяется ![alt text](http://url/to/img.png)
cs/MarkdownTests/MarkdownTests.cs
Outdated
|
||
namespace MarkdownTests; | ||
|
||
public class MarkdownTests |
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.
Весь этот класс в целом тестирует Md как чёрный ящик, что довольно сложно станет при разработке. Есть предложение сократить здесь количество тестов, а сделать отдельные классы тестов для токенайзера и генератора. Таким образом сразу будет понятно, где ошибка: при парсинге или при рендеринге
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net9.0</TargetFramework> |
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.
А в тестах всё ещё net9 прячется
[TestFixture] | ||
public class MarkdownTokenizerTests | ||
{ | ||
private MarkdownTokenizer _tokenizer; |
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.
Не стоит смешивать правила нейминга в рамках одного проекта. Ранее для приватных полей использовал уже просто с маленькой буквы. Нет единого правильного варианта - в каждом проекте решают по своему, как писать. Главное одинаково
} | ||
|
||
[Test] | ||
public void Render_ShouldRenderTagTokenWithAttributes() |
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.
Больше похоже на рендер картинки
} | ||
} | ||
|
||
_tokenizer = null; |
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.
В этом нет особого смысла, так как с ним больше ничего нигде не происходит, а в SetUp
ты его назначаешь. В основном в TearDown
производят сохранение ошибок, восстановление общих настроек. В OneTimeTearDown
могут выполнять dispose
каких-то переменных.
tokens.Should().HaveCount(1); | ||
tokens[0].Should().BeOfType<TagToken>(); | ||
tokens[0].Children![0].TextContent.Should().Be("strong text"); | ||
((TagToken)tokens[0]).Tag.Should().BeOfType<StrongTag>(); |
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.
Получится сделать с использованием .Which
?
return tree; | ||
} | ||
|
||
foreach (var tag in tagTokens) |
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.
Очень длинный и нечитаемый код. Нужно либо разбивать на методы с понятными названиями, либо переосмысливать происходящее
{ | ||
private readonly MarkdownRules markdownRules = new(); | ||
|
||
private readonly List<ITag> tags = new() |
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.
Скорее supportedTags
for (var i = 0; i < content.Length; i++) | ||
foreach (var tag in tags) | ||
{ | ||
var tagToken = new TagToken(tag) { Position = i }; |
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.
Он создаёт новый токен на КАЖДЫЙ символ на КАЖДЫЙ поддерживаемый тэг?!
{ | ||
IsTag = (tagToken, content) => | ||
(content.ContainsSubstringOnIndex(tagToken.Tag.MdClosingTag, tagToken.Position) | ||
&& content[..tagToken.Position].LastIndexOf('#') > content[..tagToken.Position].LastIndexOf('\n')) || |
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.
Для каждого вызова создаём новую строку content[..tagToken.Position]
(дважды), за ещё одну линейную сложность .LastIndexOf('#')
(дважды) не находим нужный символ. Потратили кучу памяти и много времени!
|
||
namespace MarkdownTests; | ||
|
||
public class MdTests |
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.
Вот такой тест к сожалению не пройдёт. Теряются переносы строк (учитываю, что они заменяются в твоей реализации на
, но так лучше не делать) , дублируется текст в strong и не совсем корректно обрабатывается курсив в жирном и пересечение выделений.
private const string Text = "#заголовок __с жирным текстом__\n" +
"Просто текст, в котором _курсивные_ выделения\n" +
"__Есть жирный текст__\n" +
"__А вот жирный текст _с курсивом_ внутри _и ещё курсив_ в жирном__\n" +
"_Вот __это_ не__ сработает\n" +
"_И вот так __тоже__ нет_\n" +
"Это - _ - просто подчёркивание\n" +
"Так_ не работает_\n" +
"И _ вот так _ тоже\n" +
"В с_лов_е можно выделять, а в цифрах 1_23_ нет\n" +
"Ещу можно сделать просто _курсив_\n";
private const string ExpectedResult = "<h1>заголовок <strong>с жирным текстом</strong></h1><br />" +
"Просто текст, в котором <em>курсивные</em> выделения<br />" +
"<strong>Есть жирный текст</strong><br />" +
"<strong>А вот жирный текст <em>с курсивом</em> внутри <em>и ещё курсив</em> в жирном</strong><br />" +
"_Вот __это_ не__ сработает<br />" +
"_И вот так __тоже__ нет_<br />" +
"Это - _ - просто подчёркивание<br />" +
"Так_ не работает_<br />" +
"И _ вот так _ тоже<br />" +
"В с<em>лов</em>е можно выделять, а в цифрах 1_23_ нет<br />" +
"Ещу можно сделать просто <em>курсив</em><br />";
[Test]
public void Render_ShouldReturn_HtmlString()
{
var result = new Md().Render(Text);
result.Should().Be(ExpectedResult);
}
/// </summary> | ||
/// <param name="content">Содержание</param> | ||
/// <param name="tag">Название тега</param> | ||
public class TagToken(ITag tag) : IToken |
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.
/// Текстовый токен. Содержит чистый текст | ||
/// </summary> | ||
/// <param name="content">Текст</param> | ||
public class TextToken(string content) : IToken |
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.
|
||
private void TokenizePerformanceTest(string filePath, int maxMilliseconds) | ||
{ | ||
var content = File.ReadAllText(filePath); |
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.
Это ведь шаблонный файл. Не хочешь его генерировать на лету в память, а не сохранять отдельно?
var memoryBefore = GC.GetTotalMemory(true); | ||
var result = tokenizer.Tokenize(content); | ||
var memoryAfter = GC.GetTotalMemory(false); |
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.
Не очень честный метод измерения, так как за время теста GC может всё почистить и размер получится вообще отрицательным. Но хорошо, что знаешь про API для обращения к нему
cs/Markdown/Markdown/Md.cs
Outdated
public class Md : IMd | ||
{ | ||
private readonly ITokenizer tokenizer = new MarkdownTokenizer(); |
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.
А теперь токенайзер не хранит никакое состояние и может стать полноценным приватным полем )
[Test] | ||
public void Tokenize_HeaderPerformanceTest() | ||
{ | ||
TokenizePerformanceTest("TestCases/MarkdownTokenizer/" + TestContext.CurrentContext.Test.MethodName + ".md", 200); |
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.
У меня этот тест не проходит периодически, занимает 230ms. Думаю, можно ему увеличить порог немного
No description provided.