Browse Source

Refactoring and separate transform method.

pull/104/head
Sebastian Stehle 9 years ago
parent
commit
b3fb4cf533
  1. 4
      src/Squidex.Domain.Apps.Core/Scripting/IScriptEngine.cs
  2. 77
      src/Squidex.Domain.Apps.Core/Scripting/JurassicScriptEngine.cs
  3. 6
      src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs
  4. 7
      src/Squidex/Config/Domain/WriteModule.cs
  5. 12
      src/Squidex/Controllers/ContentApi/ContentsController.cs
  6. 2
      src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs
  7. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs
  8. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs
  9. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs
  10. 1
      src/Squidex/app/features/schemas/declarations.ts
  11. 2
      src/Squidex/app/features/schemas/module.ts
  12. 12
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  13. 9
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  14. 31
      src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html
  15. 10
      src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.scss
  16. 118
      src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts
  17. 4
      src/Squidex/app/framework/angular/jscript-editor.component.ts
  18. 12
      src/Squidex/app/shared/services/schemas.service.spec.ts
  19. 24
      src/Squidex/app/shared/services/schemas.service.ts
  20. 38
      tests/Squidex.Domain.Apps.Core.Tests/Scripting/JurassicScriptEngineTests.cs
  21. 20
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs
  22. 6
      tests/Squidex.Infrastructure.Tests/Caching/InvalidatingMemoryCacheTests.cs
  23. 13
      tests/Squidex.Infrastructure.Tests/CollectionExtensionsTests.cs
  24. 0
      tests/Squidex.Infrastructure.Tests/NamedIdTests.cs

4
src/Squidex.Domain.Apps.Core/Scripting/IScriptEngine.cs

@ -14,6 +14,8 @@ namespace Squidex.Domain.Apps.Core.Scripting
{
void Execute(ScriptContext context, string script, string operationName);
NamedContentData ExecuteAndTransform(ScriptContext context, string script, string operationName, bool failOnError = false);
NamedContentData ExecuteAndTransform(ScriptContext context, string script, string operationName);
NamedContentData Transform(ScriptContext context, string script);
}
}

77
src/Squidex.Domain.Apps.Core/Scripting/JurassicScriptEngine.cs

@ -35,13 +35,16 @@ namespace Squidex.Domain.Apps.Core.Scripting
if (!string.IsNullOrWhiteSpace(script))
{
var engine = CreateScriptEngine(context, operationName);
var engine = CreateScriptEngine(context);
Execute(script, operationName, engine, true);
EnableDisallow(engine);
EnableReject(engine, operationName);
Execute(engine, script, operationName);
}
}
public NamedContentData ExecuteAndTransform(ScriptContext context, string script, string operationName, bool failOnError = false)
public NamedContentData ExecuteAndTransform(ScriptContext context, string script, string operationName)
{
Guard.NotNull(context, nameof(context));
@ -49,7 +52,10 @@ namespace Squidex.Domain.Apps.Core.Scripting
if (!string.IsNullOrWhiteSpace(script))
{
var engine = CreateScriptEngine(context, operationName);
var engine = CreateScriptEngine(context);
EnableDisallow(engine);
EnableReject(engine, operationName);
engine.SetGlobalFunction("replace", new Action<object>(data =>
{
@ -63,13 +69,39 @@ namespace Squidex.Domain.Apps.Core.Scripting
}
}));
Execute(script, operationName, engine, failOnError);
Execute(engine, script, operationName);
}
return result;
}
public NamedContentData Transform(ScriptContext context, string script)
{
Guard.NotNull(context, nameof(context));
var result = context.Data;
if (!string.IsNullOrWhiteSpace(script))
{
try
{
var engine = CreateScriptEngine(context);
engine.SetGlobalFunction("replace", new Action<object>(data =>
{
result = JsonConvert.DeserializeObject<NamedContentData>(JSONObject.Stringify(engine, data));
}));
}
catch (Exception)
{
result = context.Data;
}
}
return result;
}
private static void Execute(string script, string operationName, ScriptEngine engine, bool failOnError = false)
private static void Execute(ScriptEngine engine, string script, string operationName)
{
try
{
@ -77,25 +109,22 @@ namespace Squidex.Domain.Apps.Core.Scripting
}
catch (JavaScriptException ex)
{
if (failOnError)
{
throw new ValidationException($"Failed to {operationName} with javascript error.", new ValidationError(ex.Message));
}
throw new ValidationException($"Failed to {operationName} with javascript error.", new ValidationError(ex.Message));
}
}
private ScriptEngine CreateScriptEngine(ScriptContext context, string operationName)
private ScriptEngine CreateScriptEngine(ScriptContext context)
{
Guard.NotNullOrEmpty(operationName, nameof(operationName));
var engine = new ScriptEngine { ForceStrictMode = true };
engine.SetGlobalFunction("disallow", new Action<string>(message =>
{
var exMessage = !string.IsNullOrWhiteSpace(message) ? message : "Not allowed";
engine.SetGlobalValue("ctx", JSONObject.Parse(engine, JsonConvert.SerializeObject(context, serializerSettings)));
throw new DomainForbiddenException(exMessage);
}));
return engine;
}
private static void EnableReject(ScriptEngine engine, string operationName)
{
Guard.NotNullOrEmpty(operationName, nameof(operationName));
engine.SetGlobalFunction("reject", new Action<string>(message =>
{
@ -103,12 +132,16 @@ namespace Squidex.Domain.Apps.Core.Scripting
throw new ValidationException($"Script rejected to to {operationName}.", errors);
}));
}
var json = JsonConvert.SerializeObject(context, serializerSettings);
engine.SetGlobalValue("ctx", JSONObject.Parse(engine, json));
private static void EnableDisallow(ScriptEngine engine)
{
engine.SetGlobalFunction("disallow", new Action<string>(message =>
{
var exMessage = !string.IsNullOrWhiteSpace(message) ? message : "Not allowed";
return engine;
throw new DomainForbiddenException(exMessage);
}));
}
}
}

6
src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs

@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Write.Contents
var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command, command.Data);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptCreate, "create content", true);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptCreate, "create content");
command.Data.Enrich(schemaAndApp.SchemaEntity.Schema, schemaAndApp.AppEntity.PartitionResolver);
await ValidateAsync(schemaAndApp, command, () => "Failed to create content", false);
@ -86,7 +86,7 @@ namespace Squidex.Domain.Apps.Write.Contents
var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command, command.Data);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptUpdate, "update content", true);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptUpdate, "update content");
await ValidateAsync(schemaAndApp, command, () => "Failed to update content", false);
@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Write.Contents
var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command, command.Data);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptUpdate, "patch content", true);
command.Data = scriptEngine.ExecuteAndTransform(scriptContext, schemaAndApp.SchemaEntity.ScriptUpdate, "patch content");
await ValidateAsync(schemaAndApp, command, () => "Failed to patch content", true);

7
src/Squidex/Config/Domain/WriteModule.cs

@ -9,13 +9,14 @@
using Autofac;
using Microsoft.Extensions.Configuration;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Write.Apps;
using Squidex.Domain.Apps.Write.Assets;
using Squidex.Domain.Apps.Write.Contents;
using Squidex.Domain.Apps.Write.Schemas;
using Squidex.Domain.Apps.Write.Webhooks;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Pipeline.CommandHandlers;
using Squidex.Pipeline.CommandMiddlewares;
// ReSharper disable UnusedAutoPropertyAccessor.Local
@ -52,6 +53,10 @@ namespace Squidex.Config.Domain
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<JurassicScriptEngine>()
.As<IScriptEngine>()
.SingleInstance();
builder.RegisterType<FieldRegistry>()
.AsSelf()
.SingleInstance();

12
src/Squidex/Controllers/ContentApi/ContentsController.cs

@ -191,7 +191,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> PostContent([FromBody] NamedContentData request, [FromQuery] bool publish = false)
{
var command = new CreateContent { ContentId = Guid.NewGuid(), Data = request.ToCleaned(), Publish = publish };
var command = new CreateContent { ContentId = Guid.NewGuid(), Principal = User, Data = request.ToCleaned(), Publish = publish };
var context = await CommandBus.PublishAsync(command);
@ -207,7 +207,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> PutContent(Guid id, [FromBody] NamedContentData request)
{
var command = new UpdateContent { ContentId = id, Data = request.ToCleaned() };
var command = new UpdateContent { ContentId = id, Principal = User, Data = request.ToCleaned() };
var context = await CommandBus.PublishAsync(command);
@ -223,7 +223,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> PatchContent(Guid id, [FromBody] NamedContentData request)
{
var command = new PatchContent { ContentId = id, Data = request.ToCleaned() };
var command = new PatchContent { ContentId = id, Principal = User, Data = request.ToCleaned() };
var context = await CommandBus.PublishAsync(command);
@ -239,7 +239,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> PublishContent(Guid id)
{
var command = new PublishContent { ContentId = id };
var command = new PublishContent { ContentId = id, Principal = User };
await CommandBus.PublishAsync(command);
@ -252,7 +252,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> UnpublishContent(Guid id)
{
var command = new UnpublishContent { ContentId = id };
var command = new UnpublishContent { ContentId = id, Principal = User };
await CommandBus.PublishAsync(command);
@ -265,7 +265,7 @@ namespace Squidex.Controllers.ContentApi
[ApiCosts(1)]
public async Task<IActionResult> PutContent(Guid id)
{
var command = new DeleteContent { ContentId = id };
var command = new DeleteContent { ContentId = id, Principal = User };
await CommandBus.PublishAsync(command);

2
src/Squidex/Pipeline/CommandHandlers/ETagCommandMiddleware.cs → src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs

@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Squidex.Infrastructure.CQRS.Commands;
namespace Squidex.Pipeline.CommandHandlers
namespace Squidex.Pipeline.CommandMiddlewares
{
public class ETagCommandMiddleware : ICommandMiddleware
{

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithActorCommandMiddleware.cs → src/Squidex/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddleware.cs

@ -17,7 +17,7 @@ using Squidex.Infrastructure.Security;
// ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandHandlers
namespace Squidex.Pipeline.CommandMiddlewares
{
public class EnrichWithActorCommandMiddleware : ICommandMiddleware
{

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithAppIdCommandMiddleware.cs → src/Squidex/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs

@ -15,7 +15,7 @@ using Squidex.Infrastructure.CQRS.Commands;
// ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandHandlers
namespace Squidex.Pipeline.CommandMiddlewares
{
public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware
{

2
src/Squidex/Pipeline/CommandHandlers/EnrichWithSchemaIdCommandMiddleware.cs → src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs

@ -18,7 +18,7 @@ using Squidex.Infrastructure.CQRS.Commands;
// ReSharper disable InvertIf
namespace Squidex.Pipeline.CommandHandlers
namespace Squidex.Pipeline.CommandMiddlewares
{
public sealed class EnrichWithSchemaIdCommandMiddleware : ICommandMiddleware
{

1
src/Squidex/app/features/schemas/declarations.ts

@ -24,5 +24,6 @@ export * from './pages/schema/types/string-validation.component';
export * from './pages/schema/field.component';
export * from './pages/schema/schema-edit-form.component';
export * from './pages/schema/schema-page.component';
export * from './pages/schema/schema-scripts-form.component';
export * from './pages/schemas/schema-form.component';
export * from './pages/schemas/schemas-page.component';

2
src/Squidex/app/features/schemas/module.ts

@ -37,6 +37,7 @@ import {
SchemaFormComponent,
SchemaPageComponent,
SchemasPageComponent,
SchemaScriptsFormComponent,
StringUIComponent,
StringValidationComponent
} from './declarations';
@ -101,6 +102,7 @@ const routes: Routes = [
SchemaEditFormComponent,
SchemaFormComponent,
SchemaPageComponent,
SchemaScriptsFormComponent,
SchemasPageComponent,
StringUIComponent,
StringValidationComponent

12
src/Squidex/app/features/schemas/pages/schema/schema-page.component.html

@ -22,6 +22,9 @@
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="editOptionsDropdown" closeAlways="true" [sqxModalTarget]="optionsButton" position="right" [@fade]>
<a class="dropdown-item" (click)="configureScriptsDialog.show()">
Scripts
</a>
<a class="dropdown-item dropdown-item-delete" (sqxConfirmClick)="deleteSchema()" confirmTitle="Delete schema" confirmText="Do you really want to delete the schema?">
Delete
</a>
@ -141,4 +144,13 @@
</div>
</div>
<div class="modal" *sqxModalView="configureScriptsDialog;onRoot:true" [@fade]>
<div class="modal-backdrop"></div>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<sqx-schema-scripts-form [appName]="appName() | async" [schema]="schema" (saved)="onSchemaScriptsSaved($event)" (cancelled)="configureScriptsDialog.hide()"></sqx-schema-scripts-form>
</div>
</div>
</div>
<router-outlet></router-outlet>

9
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -27,6 +27,7 @@ import {
SchemaPropertiesDto,
SchemasService,
UpdateFieldDto,
UpdateSchemaScriptsDto,
ValidatorsEx
} from 'shared';
@ -49,6 +50,8 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
public exportSchemaDialog = new ModalView();
public configureScriptsDialog = new ModalView();
public editOptionsDropdown = new ModalView();
public editSchemaDialog = new ModalView();
@ -239,6 +242,12 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
this.editSchemaDialog.hide();
}
public onSchemaScriptsSaved(scripts: UpdateSchemaScriptsDto) {
this.updateSchema(this.schema.configureScripts(scripts, this.authService.user.token));
this.configureScriptsDialog.hide();
}
private resetFieldForm() {
this.addFieldForm.enable();
this.addFieldForm.reset({ type: 'String' });

31
src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html

@ -0,0 +1,31 @@
<form [formGroup]="editForm" (ngSubmit)="saveSchema()">
<div class="modal-header">
<h4 class="modal-title">Scripts</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="cancel()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul class="nav nav-tabs">
<li class="nav-item" *ngFor="let script of scripts">
<a class="nav-link" [class.active]="selectedField === 'script' + script" (click)="selectField('script' + script)">{{script}}</a>
</li>
</ul>
<div class="form-group">
<div *ngFor="let script of scripts">
<div *ngIf="selectedField === 'script' + script">
<sqx-jscript-editor name="script" [formControlName]="'script' + script"></sqx-jscript-editor>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="reset" class="float-left btn btn-secondary" (click)="cancel()" [disabled]="editFormSubmitted">Cancel</button>
<button type="submit" class="float-right btn btn-primary">Save</button>
</div>
</form>

10
src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.scss

@ -0,0 +1,10 @@
@import '_vars';
@import '_mixins';
.nav-link {
cursor: default;
}
.nav-tabs {
border: 0;
}

118
src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts

@ -0,0 +1,118 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {
ComponentBase,
DialogService,
SchemaDetailsDto,
SchemasService,
UpdateSchemaScriptsDto
} from 'shared';
@Component({
selector: 'sqx-schema-scripts-form',
styleUrls: ['./schema-scripts-form.component.scss'],
templateUrl: './schema-scripts-form.component.html'
})
export class SchemaScriptsFormComponent extends ComponentBase implements OnInit {
@Output()
public saved = new EventEmitter<UpdateSchemaScriptsDto>();
@Output()
public cancelled = new EventEmitter();
@Input()
public schema: SchemaDetailsDto;
@Input()
public appName: string;
public selectedField = 'scriptQuery';
public scripts = [
'Query',
'Create',
'Update',
'Delete',
'Publish',
'Unpublish'
];
public editForm =
this.formBuilder.group({
scriptQuery: '',
scriptCreate: '',
scriptUpdate: '',
scriptDelete: '',
scriptPublish: '',
scriptUnpublish: ''
});
constructor(dialogs: DialogService,
private readonly schemas: SchemasService,
private readonly formBuilder: FormBuilder
) {
super(dialogs);
}
public ngOnInit() {
this.editForm.patchValue(this.schema);
}
public cancel() {
this.emitCancelled();
this.resetEditForm();
}
public saveSchema() {
if (this.editForm.valid) {
this.editForm.disable();
const requestDto =
new UpdateSchemaScriptsDto(
this.editForm.controls['scriptQuery'].value,
this.editForm.controls['scriptCreate'].value,
this.editForm.controls['scriptUpdate'].value,
this.editForm.controls['scriptDelete'].value,
this.editForm.controls['scriptPublish'].value,
this.editForm.controls['scriptUnpublish'].value);
this.schemas.putSchemaScripts(this.appName, this.schema.name, requestDto, this.schema.version)
.subscribe(dto => {
this.emitSaved(requestDto);
this.resetEditForm();
}, error => {
this.notifyError(error);
this.enableEditForm();
});
}
}
private emitCancelled() {
this.cancelled.emit();
}
private emitSaved(requestDto: UpdateSchemaScriptsDto) {
this.saved.emit(requestDto);
}
public selectField(field: string) {
this.selectedField = field;
}
private enableEditForm() {
this.editForm.enable();
}
private resetEditForm() {
this.editForm.reset();
this.editForm.enable();
}
}

4
src/Squidex/app/framework/angular/jscript-editor.component.ts

@ -101,8 +101,8 @@ export class JscriptEditorComponent implements ControlValueAccessor, AfterViewIn
this.oldValue = newValue;
}
private setValue(value: any) {
this.aceEditor.setValue(value);
private setValue(value: string) {
this.aceEditor.setValue(value || '');
this.aceEditor.clearSelection();
}
}

12
src/Squidex/app/shared/services/schemas.service.spec.ts

@ -388,12 +388,12 @@ describe('SchemasService', () => {
}
}
],
scriptsQuery: '<script-query>',
scriptsCreate: '<script-create>',
scriptsUpdate: '<script-update>',
scriptsDelete: '<script-delete>',
scriptsPublish: '<script-publish>',
scriptsUnpublish: '<script-unpublish>'
scriptQuery: '<script-query>',
scriptCreate: '<script-create>',
scriptUpdate: '<script-update>',
scriptDelete: '<script-delete>',
scriptPublish: '<script-publish>',
scriptUnpublish: '<script-unpublish>'
});
expect(schema).toEqual(

24
src/Squidex/app/shared/services/schemas.service.ts

@ -760,12 +760,12 @@ export class SchemasService {
DateTime.parseISO_UTC(response.lastModified),
new Version(response.version.toString()),
fields,
response.scriptsQuery,
response.scriptsCreate,
response.scriptsUpdate,
response.scriptsDelete,
response.scriptsPublish,
response.scriptsUnpublish);
response.scriptQuery,
response.scriptCreate,
response.scriptUpdate,
response.scriptDelete,
response.scriptPublish,
response.scriptUnpublish);
})
.catch(error => {
if (error instanceof HttpErrorResponse && error.status === 404) {
@ -799,12 +799,12 @@ export class SchemasService {
now,
version,
dto.fields || [],
response.scriptsQuery,
response.scriptsCreate,
response.scriptsUpdate,
response.scriptsDelete,
response.scriptsPublish,
response.scriptsUnpublish);
response.scriptQuery,
response.scriptCreate,
response.scriptUpdate,
response.scriptDelete,
response.scriptPublish,
response.scriptUnpublish);
})
.do(schema => {
this.localCache.set(`schema.${appName}.${schema.id}`, schema, 5000);

38
tests/Squidex.Domain.Apps.Core.Tests/Scripting/JurassicScriptEngineTests.cs

@ -50,22 +50,31 @@ namespace Squidex.Domain.Apps.Core.Scripting
}
[Fact]
public void Should_catch_script_runtime_errors_on_transform()
public void Should_catch_script_runtime_errors_on_execute_and_transform()
{
Assert.Throws<ValidationException>(() => scriptEngine.ExecuteAndTransform(new ScriptContext(), "throw 'Error';", "update", true));
Assert.Throws<ValidationException>(() => scriptEngine.ExecuteAndTransform(new ScriptContext(), "throw 'Error';", "update"));
}
[Fact]
public void Should_return_original_content_when_script_failed()
public void Should_return_original_content_when_transform_script_failed()
{
var content = new NamedContentData();
var context = new ScriptContext { Data = content };
var result = scriptEngine.ExecuteAndTransform(context, "x => x", "update");
var result = scriptEngine.Transform(context, "x => x");
Assert.Same(content, result);
}
[Fact]
public void Should_throw_when_execute_and_transform_script_failed()
{
var content = new NamedContentData();
var context = new ScriptContext { Data = content };
Assert.Throws<ValidationException>(() => scriptEngine.ExecuteAndTransform(context, "x => x", "update"));
}
[Fact]
public void Should_return_original_content_when_content_is_not_replaced()
{
@ -78,7 +87,26 @@ namespace Squidex.Domain.Apps.Core.Scripting
}
[Fact]
public void Should_returning_empty_content_when_replacing_with_invalid_content()
public void Should_return_original_content_when_replacing_with_invalid_content_in_transform()
{
var content =
new NamedContentData()
.AddField("number0",
new ContentFieldData()
.AddValue("iv", 1))
.AddField("number1",
new ContentFieldData()
.AddValue("iv", 1));
var context = new ScriptContext { Data = content };
var result = scriptEngine.Transform(context, @"replace({ test: 1 });");
Assert.Equal(content, result);
}
[Fact]
public void Should_return_empty_content_when_replacing_with_invalid_content_in_execute_and_transform()
{
var content =
new NamedContentData()

20
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs

@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact]
public async Task Create_should_throw_exception_if_data_is_not_valid()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(invalidData);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(invalidData);
var context = CreateContextForCommand(new CreateContent { ContentId = contentId, Data = invalidData });
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact]
public async Task Create_should_create_content()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(data);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(data);
A.CallTo(() => schemaEntity.ScriptCreate).Returns("<create-script>");
var context = CreateContextForCommand(new CreateContent { ContentId = contentId, Data = data });
@ -90,13 +90,13 @@ namespace Squidex.Domain.Apps.Write.Contents
Assert.Equal(data, context.Result<EntityCreatedResult<NamedContentData>>().IdOrValue);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<create-script>", "create content", true)).MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<create-script>", "create content")).MustHaveHappened();
}
[Fact]
public async Task Update_should_throw_exception_if_data_is_not_valid()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(invalidData);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(invalidData);
CreateContent();
@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact]
public async Task Update_should_update_domain_object()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(data);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(data);
A.CallTo(() => schemaEntity.ScriptUpdate).Returns("<update-script>");
CreateContent();
@ -125,13 +125,13 @@ namespace Squidex.Domain.Apps.Write.Contents
Assert.Equal(data, context.Result<ContentDataChangedResult>().Data);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>", "update content", true)).MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>", "update content")).MustHaveHappened();
}
[Fact]
public async Task Patch_should_throw_exception_if_data_is_not_valid()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(invalidData);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(invalidData);
CreateContent();
@ -146,12 +146,12 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact]
public async Task Patch_should_update_domain_object()
{
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(data);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(data);
A.CallTo(() => schemaEntity.ScriptUpdate).Returns("<update-script>");
var path = new NamedContentData().AddField("my-field", new ContentFieldData().SetValue(3));
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored, true)).Returns(path);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored, A<string>.Ignored)).Returns(path);
CreateContent();
@ -164,7 +164,7 @@ namespace Squidex.Domain.Apps.Write.Contents
Assert.NotNull(context.Result<ContentDataChangedResult>().Data);
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>", "patch content", true)).MustHaveHappened();
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>", "patch content")).MustHaveHappened();
}
[Fact]

6
tests/Squidex.Infrastructure.Tests/Caching/InvalidatingMemoryCacheTest.cs → tests/Squidex.Infrastructure.Tests/Caching/InvalidatingMemoryCacheTests.cs

@ -16,7 +16,7 @@ using Xunit;
namespace Squidex.Infrastructure.Caching
{
public class InvalidatingMemoryCacheTest
public class InvalidatingMemoryCacheTests
{
internal sealed class MyOptions<T> : IOptions<T> where T : class, new()
{
@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.Caching
private readonly IMemoryCache cache = A.Fake<IMemoryCache>();
private readonly InvalidatingMemoryCache sut;
public InvalidatingMemoryCacheTest()
public InvalidatingMemoryCacheTests()
{
sut = new InvalidatingMemoryCache(cache, pubsub);
}
@ -99,7 +99,7 @@ namespace Squidex.Infrastructure.Caching
[Fact]
public void Should_use_inner_cache_to_get_value()
{
object outValue;
object outValue = 123;
A.CallTo(() => cache.TryGetValue("a-key", out outValue))
.Returns(true);

13
tests/Squidex.Infrastructure.Tests/CollectionExtensionsTests.cs

@ -11,7 +11,7 @@ using Xunit;
namespace Squidex.Infrastructure
{
public class CollectionExtensionTest
public class CollectionExtensionTests
{
private readonly Dictionary<int, int> valueDictionary = new Dictionary<int, int>();
private readonly Dictionary<int, List<int>> listDictionary = new Dictionary<int, List<int>>();
@ -257,5 +257,16 @@ namespace Squidex.Infrastructure
Assert.NotEqual(lhs.DictionaryHashCode(), rhs.DictionaryHashCode());
}
[Fact]
public void Foreach_should_call_action_foreach_item()
{
var source = new List<int> { 3, 5, 1 };
var target = new List<int>();
source.Foreach(target.Add);
Assert.Equal(source, target);
}
}
}

0
tests/Squidex.Infrastructure.Tests/NamedIdTest.cs → tests/Squidex.Infrastructure.Tests/NamedIdTests.cs

Loading…
Cancel
Save