Skip to content

Commit 1e1f958

Browse files
authored
Внедрение пакета System.IO.Abstractions (#12)
* внедрение абстракций I/O для возможности unit-тестирования * remove unused * тесты * coverage * new version
1 parent c133543 commit 1e1f958

File tree

10 files changed

+131
-20
lines changed

10 files changed

+131
-20
lines changed

Interpreter.Tests/MockExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Interpreter.Lib.BackEnd;
22
using Interpreter.Lib.BackEnd.Instructions;
3+
using Microsoft.Extensions.Options;
34
using Moq;
45

56
namespace Interpreter.Tests
@@ -13,5 +14,9 @@ public static Mock<Halt> Trackable(this Mock<Halt> halt)
1314
halt.Setup(x => x.End()).Returns(true);
1415
return halt;
1516
}
17+
18+
public static IOptions<CommandLineSettings> ToOptions
19+
(this Mock<CommandLineSettings> commandLineSettings) =>
20+
Options.Create(commandLineSettings.Object);
1621
}
1722
}

Interpreter.Tests/Unit/Infrastructure/ExecutorTests.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Interpreter.Services.Executor.Impl;
99
using Interpreter.Services.Parsing;
1010
using Interpreter.Tests.Stubs;
11-
using Microsoft.Extensions.Options;
1211
using Moq;
1312
using Xunit;
1413

@@ -38,7 +37,7 @@ public void ExecuteGoesOkTest()
3837
_parsingService.Setup(x => x.Parse(It.IsAny<string>()))
3938
.Returns(ast.Object);
4039

41-
var executor = new Executor(_parsingService.Object, Options.Create(_settings.Object));
40+
var executor = new Executor(_parsingService.Object, _settings.ToOptions());
4241
Assert.Null(Record.Exception(() => executor.Execute()));
4342
}
4443

@@ -52,7 +51,7 @@ public void SemanticExceptionCaughtTest()
5251
_parsingService.Setup(x => x.Parse(It.IsAny<string>()))
5352
.Returns(ast.Object);
5453

55-
var executor = new Executor(_parsingService.Object, Options.Create(_settings.Object));
54+
var executor = new Executor(_parsingService.Object, _settings.ToOptions());
5655
Assert.Null(Record.Exception(() => executor.Execute()));
5756
}
5857

@@ -62,7 +61,7 @@ public void LexerExceptionCaughtTest()
6261
_parsingService.Setup(x => x.Parse(It.IsAny<string>()))
6362
.Throws<LexerException>();
6463

65-
var executor = new Executor(_parsingService.Object, Options.Create(_settings.Object));
64+
var executor = new Executor(_parsingService.Object, _settings.ToOptions());
6665
Assert.Null(Record.Exception(() => executor.Execute()));
6766
}
6867

@@ -72,7 +71,7 @@ public void ParserExceptionCaughtTest()
7271
_parsingService.Setup(x => x.Parse(It.IsAny<string>()))
7372
.Throws<ParserException>();
7473

75-
var executor = new Executor(_parsingService.Object, Options.Create(_settings.Object));
74+
var executor = new Executor(_parsingService.Object, _settings.ToOptions());
7675
Assert.Null(Record.Exception(() => executor.Execute()));
7776
}
7877

@@ -90,7 +89,7 @@ public void InternalInterpreterErrorCaughtTest()
9089
_parsingService.Setup(x => x.Parse(It.IsAny<string>()))
9190
.Returns(ast.Object);
9291

93-
var executor = new Executor(_parsingService.Object, Options.Create(_settings.Object));
92+
var executor = new Executor(_parsingService.Object, _settings.ToOptions());
9493
Assert.Null(Record.Exception(() => executor.Execute()));
9594
}
9695
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using System.Collections.Generic;
2+
using System.IO.Abstractions;
3+
using System.Linq;
4+
using Interpreter.Lib.BackEnd.Instructions;
5+
using Interpreter.Lib.FrontEnd.GetTokens;
6+
using Interpreter.Lib.FrontEnd.GetTokens.Data;
7+
using Interpreter.Lib.FrontEnd.TopDownParse;
8+
using Interpreter.Lib.IR.Ast;
9+
using Interpreter.Services.Providers.Impl.LexerProvider;
10+
using Interpreter.Services.Providers.Impl.ParserProvider;
11+
using Moq;
12+
using Xunit;
13+
14+
namespace Interpreter.Tests.Unit.Infrastructure
15+
{
16+
public class LoggingEntitiesTests
17+
{
18+
private readonly Mock<IFile> _file;
19+
private readonly Mock<IFileSystem> _fileSystem;
20+
21+
public LoggingEntitiesTests()
22+
{
23+
_file = new Mock<IFile>();
24+
25+
_fileSystem = new Mock<IFileSystem>();
26+
_fileSystem.Setup(x => x.File)
27+
.Returns(_file.Object);
28+
}
29+
30+
[Fact]
31+
public void CorrectFileNameProducedByLexerTest()
32+
{
33+
var lexer = new Mock<ILexer>();
34+
lexer.Setup(x => x.GetTokens(It.IsAny<string>()))
35+
.Returns(new List<Token>());
36+
lexer.Setup(x => x.ToString())
37+
.Returns("lexer");
38+
39+
_file.Setup(x => x.WriteAllText(
40+
It.IsAny<string>(), It.IsAny<string>()
41+
)).Verifiable();
42+
43+
var loggingLexer = new LoggingLexer(lexer.Object, "file", _fileSystem.Object);
44+
loggingLexer.GetTokens("");
45+
46+
_file.Verify(x => x.WriteAllText(
47+
It.Is<string>(p => p == "file.tokens"), It.Is<string>(c => c == "lexer")
48+
), Times.Once());
49+
}
50+
51+
[Fact]
52+
public void CorrectTreeWrittenAndLoggingTreeProducedTest()
53+
{
54+
var ast = new Mock<IAbstractSyntaxTree>();
55+
ast.Setup(x => x.ToString())
56+
.Returns("digraph ast { }");
57+
58+
var parser = new Mock<IParser>();
59+
parser.Setup(x => x.TopDownParse(It.IsAny<string>()))
60+
.Returns(ast.Object);
61+
62+
_file.Setup(x => x.WriteAllText(
63+
It.IsAny<string>(), It.IsAny<string>()
64+
)).Verifiable();
65+
66+
var loggingParser = new LoggingParser(parser.Object, "file", _fileSystem.Object);
67+
var parsed = loggingParser.TopDownParse("");
68+
69+
_file.Verify(x => x.WriteAllText(
70+
It.Is<string>(p => p == "ast.dot"),
71+
It.Is<string>(c => c == "digraph ast { }")
72+
), Times.Once());
73+
Assert.IsType<LoggingAbstractSyntaxTree>(parsed);
74+
}
75+
76+
[Fact]
77+
public void CorrectFileNameProducedByTreeTest()
78+
{
79+
var ast = new Mock<IAbstractSyntaxTree>();
80+
ast.Setup(x => x.GetInstructions())
81+
.Returns(new List<Instruction> { new Halt(0) });
82+
83+
_file.Setup(x => x.WriteAllLines(
84+
It.IsAny<string>(), It.IsAny<IEnumerable<string>>()
85+
)).Verifiable();
86+
87+
var loggingTree = new LoggingAbstractSyntaxTree(ast.Object, "file", _fileSystem.Object);
88+
loggingTree.GetInstructions();
89+
90+
_file.Verify(x => x.WriteAllLines(
91+
It.Is<string>(p => p == "file.tac"),
92+
It.Is<IEnumerable<string>>(c => c.SequenceEqual(new[] { "0: End" }))
93+
), Times.Once());
94+
}
95+
}
96+
}

Interpreter/Interpreter.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net6.0</TargetFramework>
6-
<Version>1.1.2</Version>
6+
<Version>1.1.3</Version>
77
</PropertyGroup>
88

99
<ItemGroup>
@@ -15,6 +15,7 @@
1515
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
1616
<PackageReference Include="CommandLineParser" Version="2.9.1" />
1717
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
18+
<PackageReference Include="System.IO.Abstractions" Version="17.2.1" />
1819
</ItemGroup>
1920

2021
</Project>

Interpreter/Services/Providers/Impl/LexerProvider/LexerProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.IO.Abstractions;
12
using AutoMapper;
23
using Interpreter.Lib.FrontEnd.GetTokens;
34
using Interpreter.Lib.FrontEnd.GetTokens.Data;
@@ -23,7 +24,7 @@ public ILexer CreateLexer()
2324
var domain = _mapper.Map<StructureModel, Structure>(_settings.StructureModel);
2425
var lexer = new Lexer(domain);
2526
return _settings.Dump
26-
? new LoggingLexer(lexer, _settings.GetInputFileName())
27+
? new LoggingLexer(lexer, _settings.GetInputFileName(), new FileSystem())
2728
: lexer;
2829
}
2930
}

Interpreter/Services/Providers/Impl/LexerProvider/LoggingLexer.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
2-
using System.IO;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.IO.Abstractions;
34
using Interpreter.Lib.FrontEnd.GetTokens;
45
using Interpreter.Lib.FrontEnd.GetTokens.Data;
56

@@ -9,19 +10,22 @@ public class LoggingLexer : ILexer
910
{
1011
private readonly ILexer _lexer;
1112
private readonly string _fileName;
13+
private readonly IFileSystem _fileSystem;
1214

13-
public LoggingLexer(ILexer lexer, string fileName)
15+
public LoggingLexer(ILexer lexer, string fileName, IFileSystem fileSystem)
1416
{
1517
_lexer = lexer;
1618
_fileName = fileName;
19+
_fileSystem = fileSystem;
1720
}
1821

22+
[ExcludeFromCodeCoverage]
1923
public Structure Structure => _lexer.Structure;
2024

2125
public List<Token> GetTokens(string text)
2226
{
2327
var tokens = _lexer.GetTokens(text);
24-
File.WriteAllText(
28+
_fileSystem.File.WriteAllText(
2529
$"{_fileName}.tokens",
2630
_lexer.ToString()
2731
);

Interpreter/Services/Providers/Impl/ParserProvider/LoggingAbstractSyntaxTree.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Collections.Generic;
2-
using System.IO;
2+
using System.IO.Abstractions;
33
using System.Linq;
44
using Interpreter.Lib.BackEnd.Instructions;
55
using Interpreter.Lib.IR.Ast;
@@ -10,17 +10,19 @@ public class LoggingAbstractSyntaxTree : IAbstractSyntaxTree
1010
{
1111
private readonly IAbstractSyntaxTree _ast;
1212
private readonly string _fileName;
13+
private readonly IFileSystem _fileSystem;
1314

14-
public LoggingAbstractSyntaxTree(IAbstractSyntaxTree ast, string fileName)
15+
public LoggingAbstractSyntaxTree(IAbstractSyntaxTree ast, string fileName, IFileSystem fileSystem)
1516
{
1617
_ast = ast;
1718
_fileName = fileName;
19+
_fileSystem = fileSystem;
1820
}
1921

2022
public List<Instruction> GetInstructions()
2123
{
2224
var instructions = _ast.GetInstructions();
23-
File.WriteAllLines(
25+
_fileSystem.File.WriteAllLines(
2426
$"{_fileName}.tac",
2527
instructions.OrderBy(i => i).Select(i => i.ToString())
2628
);
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.IO;
1+
using System.IO.Abstractions;
22
using Interpreter.Lib.FrontEnd.TopDownParse;
33
using Interpreter.Lib.IR.Ast;
44

@@ -8,19 +8,21 @@ public class LoggingParser : IParser
88
{
99
private readonly IParser _parser;
1010
private readonly string _fileName;
11+
private readonly IFileSystem _fileSystem;
1112

12-
public LoggingParser(IParser parser, string fileName)
13+
public LoggingParser(IParser parser, string fileName, IFileSystem fileSystem)
1314
{
1415
_parser = parser;
1516
_fileName = fileName;
17+
_fileSystem = fileSystem;
1618
}
1719

1820
public IAbstractSyntaxTree TopDownParse(string text)
1921
{
2022
var ast = _parser.TopDownParse(text);
2123
var astDot = ast.ToString();
22-
File.WriteAllText("ast.dot", astDot);
23-
return new LoggingAbstractSyntaxTree(ast, _fileName);
24+
_fileSystem.File.WriteAllText("ast.dot", astDot);
25+
return new LoggingAbstractSyntaxTree(ast, _fileName, _fileSystem);
2426
}
2527
}
2628
}

Interpreter/Services/Providers/Impl/ParserProvider/ParserProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.IO.Abstractions;
12
using Interpreter.Lib.FrontEnd.TopDownParse;
23
using Parser = Interpreter.Lib.FrontEnd.TopDownParse.Impl.Parser;
34
using Microsoft.Extensions.Options;
@@ -20,7 +21,7 @@ public IParser CreateParser()
2021
var lexer = _lexerProvider.CreateLexer();
2122
var parser = new Parser(lexer);
2223
return _settings.Dump
23-
? new LoggingParser(parser, _settings.GetInputFileName())
24+
? new LoggingParser(parser, _settings.GetInputFileName(), new FileSystem())
2425
: parser;
2526
}
2627
}

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ let s = v2d as string
174174
### Запуск
175175

176176
```
177-
Interpreter 1.1.2
177+
Interpreter 1.1.3
178178
Copyright (C) 2022 Interpreter
179179
USAGE:
180180
Simple interpretation call:

0 commit comments

Comments
 (0)