Skip to content
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

Зайцев ДА #28

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions ConsoleClient/ConsoleClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using McMaster.Extensions.CommandLineUtils;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хочется в репозитории иметь примеры генерации изображений твоим кодом. Чтобы наглядно видеть про изменения размеров и так далее. Хотя бы тестах

using Autofac;
using TagsCloudContainer;

public class ConsoleClient
{
[Option("--input", "Path to the input file.", CommandOptionType.SingleValue)]
public string? InputDirectory { get; set; }

[Option("--output", "Path to the output file.", CommandOptionType.SingleValue)]
public string? OutputDirectory { get; set; }

[Option("--width", "Width of the picture.", CommandOptionType.SingleValue)]
public int PictureWidth { get; set; }

[Option("--height", "Height of the picture.", CommandOptionType.SingleValue)]
public int PictureHeight { get; set; }

[Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)]
public string? Font { get; set; }

[Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)]
public string? StopWordsInput { get; set; }

[Option("--rightwords", "Comma-separated list of right words.", CommandOptionType.SingleValue)]
public string? RightWordsInput { get; set; }

[Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)]
public string? ColorsInput { get; set; }

public static int Main(string[] args)
{
return RunConsoleClient(args);
}

private static int RunConsoleClient(string[] args)
{
return CommandLineApplication.Execute<ConsoleClient>(args);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Стоит разделить ответственности: ответственность запуска и ответственность логики работы консольного клиента

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут нужно было разделить класс на два:

  1. Метод Main - про запуск приложения, отдельный класс, что-то типо EntryPoint.cs
  2. ConsoleClient - про настройки и свойства (InputDirectory и остальные), а также метод запуски консольного клиента

В целом, можно было вынести только настройки и свойства в отдельный класс и уже было бы сильно хорошо

Зачем это делать? Две ответственности: про запуск приложения и про логику непосредственно приложения. Например, на консольный клиент может захотеться написать тест. В текущем виде он неразрывен от метода Main, что будет неправильно затаскивать в тесты

}

private void OnExecute()
{
var config = new Config(
InputDirectory ?? Constants.InputDirectory,
OutputDirectory ?? Constants.OutputDirectory,
PictureWidth == default ? Constants.PictureWidth : PictureWidth,
PictureHeight == default ? Constants.PictureHeight : PictureHeight,
Font ?? Constants.Font,
StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Constants.StopWords,
RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Constants.RightWords,
ColorsInput?.Split(',') ?? Constants.PictureColors
);

var container = ApplicationRunner.BuildContainer(config);

using var scope = container.BeginLifetimeScope();
var runner = scope.Resolve<IApplicationRunner>();
runner.Run();
}


}


18 changes: 18 additions & 0 deletions ConsoleClient/ConsoleClient.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
</ItemGroup>

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

</Project>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
150 changes: 150 additions & 0 deletions TagCloudContainerTests/CircularCloudLayouterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using FluentAssertions;
using NUnit.Framework.Interfaces;
using System.Drawing;
using TagsCloudContainer;
using TagsCloudContainer.Layouters;
using TagsCloudContainer.Visualizers;
using TagsCloudContainer.WordClasses;

namespace TagCloudContainerTests;

[TestFixture]
public class CircularCloudLayouterTests
{

private CircularCloudLayouter layouter;
private Config config;
private IVisualizer visualizer;

private readonly string text = "text";
private readonly Font font = new("Arial", 15);

[SetUp]
public void Setup()
{
config = new Config();
layouter = new CircularCloudLayouter(config);
visualizer = new ImageVisualizer(config);
}

[TearDown]
public void Teardown()
{
var testResult = TestContext.CurrentContext.Result.Outcome;
var testName = TestContext.CurrentContext.Test.Name;
if (Equals(testResult, ResultState.Failure) ||
Equals(testResult == ResultState.Error))
{
var drawer = visualizer;
var directory = Path.Combine(Constants.ProjectDirectory, $"FailedTestTagCloud.{testName}.jpeg");
config.OutputDirectory = directory;
drawer.GenerateImage(layouter.Rectangles);
Console.WriteLine($"Tag cloud visualization saved to file {directory}");
}
}

private SizeWord GetDefaultSizeWord(Size size)
{
return new SizeWord(text, size, font);
}

[Test]
public void CircularCloudLayouter_Constructor_CorrectlySetCenter()
{
layouter.GetLayout([]);

layouter.Center
.Should()
.Be(new Point(config.PictureWidth / 2, config.PictureHeight / 2));
}

[Test]
public void PutNextRectangle_PlacesFirstRectangleToCenter()
{
var size = new Size(50, 50);

var rectangles = layouter.GetLayout([GetDefaultSizeWord(size)]);
var centerRecLocation = CircularCloudLayouter.
GetCornerPoint(layouter.Center, size);

rectangles
.First()
.Bounds
.Location
.Should()
.Be(centerRecLocation);
}

[Test]
public void PutNextRectangle_RectanglesDoesNotIntersect()
{
var sizeList = new List<SizeWord>();

for (int i = 10; i < 100; i += 10)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Снова про явные типы и var

for (int j = 5; j < 50; j += 5)
sizeList.Add(GetDefaultSizeWord(new Size(i, j)));

var rectangles = layouter.GetLayout(sizeList);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не используется

var length = layouter.Rectangles.Count;
for (int i = 0; i < length - 1; i++)
for (int j = 0; j < length - 1; j++)
{
if (i != j)
layouter.Rectangles[i]
.Bounds
.IntersectsWith(layouter.Rectangles[j].Bounds)
.Should().BeFalse();
}
}

[Test]
public void PutNextRectangle_IncreaseDistanceFromCenter_WithMoreRectangles()
{
var sizeList = new List<SizeWord>
{
GetDefaultSizeWord(new Size(20,10))
};

for (int i = 10; i < 100; i += 10)
for (int j = 10; j < 50; j += 10)
sizeList.Add(GetDefaultSizeWord(new Size(i, j)));
sizeList.Add(GetDefaultSizeWord(new (20, 30)));

var rectangles = layouter.GetLayout(sizeList);
var firstRectangle = rectangles.First();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не исправлено

var lastRectangle = rectangles.Last();

var firstDistance = FindDistance(layouter.Center, firstRectangle.Bounds.Location);
var lastDistance = FindDistance(layouter.Center, lastRectangle.Bounds.Location);

lastDistance.Should().BeGreaterThan(firstDistance);
}

private double FindDistance(Point r1, Point r2)
{
return Math.Sqrt(Math.Pow(r2.X - r1.X, 2) + Math.Pow(r2.Y - r1.Y, 2));
}

[Test]
public void PutNextRectangle_ShouldPlaceRectanglesInSpiral()
{
var sizeList = new List<SizeWord>
{
GetDefaultSizeWord(new Size(10,10)),
GetDefaultSizeWord(new Size(10,10)),
GetDefaultSizeWord(new Size(10,10)),
GetDefaultSizeWord(new Size(10,10)),
GetDefaultSizeWord(new Size(10,10))
};

var rectangles = layouter.GetLayout(sizeList);
var firstRectangle = rectangles.First().Bounds;

CircularCloudLayouter.GetCenterPoint(firstRectangle).Should().Be(layouter.Center);
for (int i = 1; i < 4; i++)
{
var rect = layouter.Rectangles[i];
FindDistance(firstRectangle.Location, rect.Bounds.Location).Should().BeLessThan(30);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как этот тест доказывает, что прямоугольники расположены по спирали?

}
}
}
56 changes: 56 additions & 0 deletions TagCloudContainerTests/FileReadTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using TagsCloudContainer.FileReaders;

namespace TagCloudContainerTests;

[TestFixture]
public class FileReadTest

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Предлагаю такие тяжелые тесты запускать в параллель

{
private static readonly VerifySettings Settings = new();
private IReader Reader;
private string FolderPath;

[SetUp]
public void Setup()
{
Settings.UseDirectory("Snapshots");
var projectDirectory =
Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\"));
FolderPath = Path.Combine(projectDirectory, "Files");
}

[Test]
[Parallelizable(ParallelScope.Self)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно проще - [Parallelizable(ParallelScope.All)] на весь класс

public Task Reader_TxtReading()
{
Reader = new TxtFileReader();

var filePath = Path.Combine(FolderPath, "wordsTXT.txt");
var actual = Reader.Read(filePath);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай разделять пустыми строками блоки AAA


return Verify(actual, Settings);
}

[Test]
[Parallelizable(ParallelScope.Self)]
public Task Reader_DocxReading()
{
Reader = new DocxFileReader();

var filePath = Path.Combine(FolderPath, "wordsDOCX.docx");
var actual = Reader.Read(filePath);

return Verify(actual, Settings);
}

[Test]
[Parallelizable(ParallelScope.Self)]
public Task Reader_DocReading()
{
Reader = new DocFileReader();

var filePath = Path.Combine(FolderPath, "wordsDOC.doc");
var actual = Reader.Read(filePath);

return Verify(actual, Settings);
}
}
Binary file added TagCloudContainerTests/Files/wordsDOC.doc
Binary file not shown.
Binary file added TagCloudContainerTests/Files/wordsDOCX.docx
Binary file not shown.
Loading