Skip to content

Commit abf998f

Browse files
authored
Merge pull request #1617 from SoftUni-Internal/v2-development
Merge dev into main. Integrate latest bug fixes and improvements.
2 parents a189880 + 135a814 commit abf998f

File tree

6 files changed

+210
-2
lines changed

6 files changed

+210
-2
lines changed

Services/Common/OJS.Workers/OJS.Workers.Common/ExecutionStrategiesConstants.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public static class ExecutionStrategyNames
5151

5252
// TypeScript
5353
public const string TypeScriptCodeV20 = "typescript-codeV20";
54+
public const string TypeScriptUnitTestsWithMochaV20 = "typescript-unit-tests-with-mochaV20";
5455

5556
// Python
5657
public const string PythonCode = "python-code";
@@ -149,7 +150,8 @@ public static class NameMappings
149150
{ ExecutionStrategyNames.JavaScriptCodeAgainstUnitTestsWithMochaV20, ExecutionStrategyType.NodeJsV20PreprocessExecuteAndRunCodeAgainstUnitTestsWithMochaExecutionStrategy },
150151

151152
// TypeScript
152-
{ ExecutionStrategyNames.TypeScriptCodeV20, ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndCheck },
153+
{ ExecutionStrategyNames.TypeScriptCodeV20, ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndCheck },
154+
{ ExecutionStrategyNames.TypeScriptUnitTestsWithMochaV20, ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMocha },
153155

154156
// Java
155157
{ ExecutionStrategyNames.JavaCode, ExecutionStrategyType.JavaPreprocessCompileExecuteAndCheck },

Services/Common/OJS.Workers/OJS.Workers.Common/Models/ExecutionStrategyType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,6 @@ public enum ExecutionStrategyType
6969
NodeJsV20ZipExecuteHtmlAndCssStrategy = 72,
7070
NodeJsV20RunSpaAndExecuteMochaTestsExecutionStrategySeparateTests = 73,
7171
TypeScriptV20PreprocessExecuteAndCheck = 74,
72+
TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMocha = 75,
7273
}
7374
}

Services/Common/OJS.Workers/OJS.Workers.ExecutionStrategies/Helpers/JsCodePreEvaluationCodeProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ ExecutionStrategyType.NodeJsV20PreprocessExecuteAndCheck or
1414
=> GetForNodeJsPreprocessExecuteAndCheck(),
1515

1616
ExecutionStrategyType.NodeJsPreprocessExecuteAndRunUnitTestsWithMocha or
17-
ExecutionStrategyType.NodeJsV20PreprocessExecuteAndRunUnitTestsWithMocha
17+
ExecutionStrategyType.NodeJsV20PreprocessExecuteAndRunUnitTestsWithMocha or
18+
ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMocha
1819
=> GetForNodeJsPreprocessExecuteAndRunUnitTestsWithMocha(),
1920

2021
ExecutionStrategyType.NodeJsPreprocessExecuteAndRunJsDomUnitTests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
namespace OJS.Workers.ExecutionStrategies.NodeJs.Typescript;
2+
3+
using Microsoft.Extensions.Logging;
4+
using System.Collections.Generic;
5+
using System.Threading.Tasks;
6+
using System.Linq;
7+
using OJS.Workers.Common;
8+
using OJS.Workers.Common.Extensions;
9+
using OJS.Workers.Common.Helpers;
10+
using OJS.Workers.Common.Models;
11+
using OJS.Workers.Compilers;
12+
using OJS.Workers.ExecutionStrategies.Models;
13+
using OJS.Workers.Executors;
14+
15+
public class TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategy<TSettings>(
16+
IOjsSubmission submission,
17+
IProcessExecutorFactory processExecutorFactory,
18+
IExecutionStrategySettingsProvider settingsProvider,
19+
ILogger<BaseExecutionStrategy<TSettings>> logger,
20+
ICompilerFactory compilerFactory)
21+
: NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategy<TSettings>(submission, processExecutorFactory,
22+
settingsProvider, logger)
23+
where TSettings : NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategySettings
24+
{
25+
protected const string TestsPlaceholder = "/*#testsCode*/";
26+
protected const string UserCodePlaceholder = "/*#userCode#*/";
27+
protected const string SolutionSkeletonPlaceholder = "/*#solutionSkeleton#*/";
28+
29+
private string TypeScriptTemplateContent => @$"
30+
// Imports
31+
// @ts-ignore
32+
const chai = require('{this.Settings.ChaiModulePath}');
33+
// @ts-ignore
34+
const sinon = require('{this.Settings.SinonModulePath}');
35+
// @ts-ignore
36+
const sinonChai = require('{this.Settings.SinonChaiModulePath}');
37+
38+
chai.use(sinonChai);
39+
40+
const expect = chai.expect;
41+
const assert = chai.assert;
42+
const should = chai.should();
43+
44+
// Skeleton
45+
{SolutionSkeletonPlaceholder}
46+
47+
// User code
48+
let result = {UserCodePlaceholder}
49+
50+
// Tests
51+
// @ts-ignore
52+
describe('Tests', function () {{
53+
{TestsPlaceholder}
54+
}});
55+
";
56+
57+
protected override async Task<IExecutionResult<TestResult>> ExecuteAgainstTestsInput(
58+
IExecutionContext<TestsInputModel> executionContext,
59+
IExecutionResult<TestResult> result)
60+
{
61+
// Prepare TypeScript file with combined user code and tests
62+
var typeScriptTemplate = this.TypeScriptTemplateContent;
63+
var userCode = executionContext.Code.Trim();
64+
typeScriptTemplate = typeScriptTemplate
65+
.Replace(SolutionSkeletonPlaceholder, executionContext.Input.TaskSkeletonAsString)
66+
.Replace(UserCodePlaceholder, userCode);
67+
68+
// Process each test and wrap it in an it() block with @ts-ignore
69+
if (executionContext.Input.Tests.Any())
70+
{
71+
var formattedTests = FormatTests(executionContext.Input.Tests);
72+
typeScriptTemplate = typeScriptTemplate.Replace(TestsPlaceholder, formattedTests);
73+
}
74+
75+
// Save the combined TypeScript file
76+
var tsCodeSavePath = FileHelpers.SaveStringToTempFile(this.WorkingDirectory, typeScriptTemplate);
77+
78+
// Run TypeScript compiler to generate JavaScript
79+
var compiler = compilerFactory.CreateCompiler(executionContext.CompilerType, this.Type);
80+
var compilerPath = compilerFactory.GetCompilerPath(executionContext.CompilerType, this.Type);
81+
var compilerResult = compiler.Compile(compilerPath, tsCodeSavePath, executionContext.AdditionalCompilerArguments);
82+
83+
if (!compilerResult.IsCompiledSuccessfully)
84+
{
85+
result.IsCompiledSuccessfully = false;
86+
result.CompilerComment = compilerResult.CompilerComment;
87+
return result;
88+
}
89+
90+
// Execute tests using Node.js on the generated JavaScript file
91+
var executor = this.CreateRestrictedExecutor();
92+
var checker = executionContext.Input.GetChecker();
93+
94+
var testResults = await this.ProcessTests(
95+
executionContext,
96+
executor,
97+
checker,
98+
compilerResult.OutputFile);
99+
result.Results.AddRange(testResults);
100+
101+
return result;
102+
}
103+
104+
private static string FormatTests(IEnumerable<TestContext> tests)
105+
{
106+
var formattedTests = new List<string>();
107+
var testCounter = 1;
108+
109+
foreach (var test in tests)
110+
{
111+
// Use simple sequential test names
112+
var testName = $"Test{testCounter}";
113+
var testContent = test.Input.Trim();
114+
115+
// Format the test with proper it() wrapper
116+
var formattedTest = $@"
117+
// @ts-ignore
118+
it('{testName}', function () {{
119+
{testContent}
120+
}})";
121+
122+
formattedTests.Add(formattedTest);
123+
testCounter++;
124+
}
125+
126+
// Join all formatted tests
127+
return string.Join("\n", formattedTests);
128+
}
129+
130+
protected override async Task<List<TestResult>> ProcessTests(
131+
IExecutionContext<TestsInputModel> executionContext,
132+
IExecutor executor,
133+
IChecker checker,
134+
string codeSavePath)
135+
{
136+
var testResults = new List<TestResult>();
137+
138+
// Configure arguments for Mocha with Node.js
139+
var arguments = new List<string>
140+
{
141+
this.Settings.MochaModulePath,
142+
codeSavePath,
143+
"--reporter", "json"
144+
};
145+
arguments.AddRange(this.AdditionalExecutionArguments);
146+
147+
// Execute Mocha with Node.js
148+
var processExecutionResult = await executor.Execute(
149+
this.Settings.NodeJsExecutablePath,
150+
executionContext.TimeLimit,
151+
executionContext.MemoryLimit,
152+
string.Empty,
153+
arguments);
154+
155+
// Parse the results
156+
var mochaResult = JsonExecutionResult.Parse(processExecutionResult.ReceivedOutput);
157+
158+
// Map results to each test
159+
var currentTest = 0;
160+
foreach (var test in executionContext.Input.Tests)
161+
{
162+
var message = "yes";
163+
if (!string.IsNullOrEmpty(mochaResult.Error))
164+
{
165+
message = mochaResult.Error;
166+
}
167+
else if (currentTest < mochaResult.TestErrors.Count && mochaResult.TestErrors[currentTest] != null)
168+
{
169+
message = $"Test failed: {mochaResult.TestErrors[currentTest]}";
170+
}
171+
172+
var testResult = CheckAndGetTestResult(
173+
test,
174+
processExecutionResult,
175+
checker,
176+
message);
177+
178+
currentTest++;
179+
testResults.Add(testResult);
180+
}
181+
182+
return testResults;
183+
}
184+
}

Services/Worker/OJS.Services.Worker.Business/Implementations/ExecutionStrategyFactory.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ public IExecutionStrategy CreateExecutionStrategy(IOjsSubmission submission)
178178
loggerFactory.CreateStrategyLogger<TypeScriptPreprocessExecuteAndCheckExecutionStrategy<TypeScriptPreprocessExecuteAndCheckExecutionStrategySettings>>(submissionId, verbosely, logFileMaxBytes),
179179
compilerFactory);
180180
break;
181+
case ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMocha:
182+
executionStrategy = new TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategy<NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategySettings>(
183+
submission,
184+
processExecutorFactory,
185+
executionStrategySettingsProvider,
186+
loggerFactory.CreateStrategyLogger<TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategy<NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategySettings>>(submissionId, verbosely, logFileMaxBytes),
187+
compilerFactory);
188+
break;
181189
case ExecutionStrategyType.NodeJsPreprocessExecuteAndRunUnitTestsWithMocha:
182190
case ExecutionStrategyType.NodeJsV20PreprocessExecuteAndRunUnitTestsWithMocha:
183191
executionStrategy = new NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategy<NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategySettings>(

Services/Worker/OJS.Services.Worker.Business/Implementations/ExecutionStrategySettingsProvider.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ ExecutionStrategyType.NodeJsPreprocessExecuteAndCheck or
5858
this.GetNodeJsExecutablePath(executionStrategyType),
5959
this.GetNodeResourcePath(executionStrategyType, this.settings.UnderscoreModulePath))
6060

61+
as TSettings,
62+
ExecutionStrategyType.TypeScriptV20PreprocessExecuteAndRunUnitTestsWithMocha => new
63+
NodeJsPreprocessExecuteAndRunUnitTestsWithMochaExecutionStrategySettings(
64+
GetBaseTimeUsed(submission, this.settings.NodeJsBaseTimeUsedInMilliseconds * 2),
65+
GetBaseMemoryUsed(submission, this.settings.NodeJsBaseMemoryUsedInBytes),
66+
this.GetNodeJsExecutablePath(executionStrategyType),
67+
this.GetNodeResourcePath(executionStrategyType, this.settings.UnderscoreModulePath),
68+
this.GetNodeResourcePath(executionStrategyType, this.settings.MochaModulePath),
69+
this.GetNodeResourcePath(executionStrategyType, this.settings.ChaiModulePath),
70+
this.GetNodeResourcePath(executionStrategyType, this.settings.SinonModulePath),
71+
this.GetNodeResourcePath(executionStrategyType, this.settings.SinonChaiModulePath))
72+
6173
as TSettings,
6274
ExecutionStrategyType.JavaPreprocessCompileExecuteAndCheck or
6375
ExecutionStrategyType.Java21PreprocessCompileExecuteAndCheck => new

0 commit comments

Comments
 (0)