mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fix exported WebManifest file having a syntax error when the game description has line breaks
Fix #4180
This commit is contained in:
@@ -929,7 +929,7 @@ const gd::String ExporterHelper::GenerateWebManifest(
|
||||
icons +=
|
||||
gd::String(R"({
|
||||
"src": "{FILE}",
|
||||
"sizes": "{SIZE}x{SIZE}"
|
||||
"sizes": "{SIZE}x{SIZE}"
|
||||
},)")
|
||||
.FindAndReplace("{SIZE}", gd::String::From(sizeAndFile.first))
|
||||
.FindAndReplace("{FILE}", sizeAndFile.second);
|
||||
@@ -938,11 +938,18 @@ const gd::String ExporterHelper::GenerateWebManifest(
|
||||
|
||||
icons = icons.RightTrim(",") + "]";
|
||||
|
||||
gd::String jsonName =
|
||||
gd::Serializer::ToJSON(gd::SerializerElement(project.GetName()));
|
||||
gd::String jsonPackageName =
|
||||
gd::Serializer::ToJSON(gd::SerializerElement(project.GetPackageName()));
|
||||
gd::String jsonDescription =
|
||||
gd::Serializer::ToJSON(gd::SerializerElement(project.GetDescription()));
|
||||
|
||||
return gd::String(R"webmanifest({
|
||||
"name": "{NAME}",
|
||||
"short_name": "{NAME}",
|
||||
"id": "{PACKAGE_ID}",
|
||||
"description": "{DESCRIPTION}",
|
||||
"name": {NAME},
|
||||
"short_name": {NAME},
|
||||
"id": {PACKAGE_ID},
|
||||
"description": {DESCRIPTION},
|
||||
"orientation": "{ORIENTATION}",
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
@@ -950,9 +957,9 @@ const gd::String ExporterHelper::GenerateWebManifest(
|
||||
"categories": ["games", "entertainment"],
|
||||
"icons": {ICONS}
|
||||
})webmanifest")
|
||||
.FindAndReplace("{NAME}", project.GetName())
|
||||
.FindAndReplace("{PACKAGE_ID}", project.GetPackageName())
|
||||
.FindAndReplace("{DESCRIPTION}", project.GetDescription())
|
||||
.FindAndReplace("{NAME}", jsonName)
|
||||
.FindAndReplace("{PACKAGE_ID}", jsonPackageName)
|
||||
.FindAndReplace("{DESCRIPTION}", jsonDescription)
|
||||
.FindAndReplace("{ORIENTATION}",
|
||||
orientation == "default" ? "any" : orientation)
|
||||
.FindAndReplace("{ICONS}", icons);
|
||||
|
@@ -17,7 +17,17 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
|
||||
describe('Exporter', () => {
|
||||
// Fake files to simulate a file system (see tests below).
|
||||
const fakeIndexHtmlContent = '';
|
||||
const fakeIndexHtmlContent = `<html>
|
||||
<head>
|
||||
<style>
|
||||
/* GDJS_CUSTOM_STYLE */
|
||||
</style>
|
||||
<!-- GDJS_CODE_FILES -->
|
||||
<body>
|
||||
<!-- GDJS_CUSTOM_HTML -->
|
||||
</body>
|
||||
</head>
|
||||
</html>`;
|
||||
const fakeConfigXmlContent = `
|
||||
<widget id="GDJS_PACKAGENAME" version="GDJS_PROJECTVERSION">
|
||||
<name>GDJS_PROJECTNAME</name>
|
||||
@@ -38,6 +48,56 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
"author": "GDJS_GAME_AUTHOR"
|
||||
}`;
|
||||
|
||||
it('properly exports HTML5 files', () => {
|
||||
// Create a simple project
|
||||
const project = gd.ProjectHelper.createNewGDJSProject();
|
||||
project.setName('My great project with spaces and "quotes"!');
|
||||
project.setDescription(
|
||||
'A nice project\nwith line breaks in the description.'
|
||||
);
|
||||
project.setVersion('1.2.3');
|
||||
|
||||
// Prepare a fake file system
|
||||
var fs = makeFakeAbstractFileSystem(gd, {
|
||||
'/fake-gdjs-root/Runtime/index.html': fakeIndexHtmlContent,
|
||||
});
|
||||
|
||||
// Export and check the content of written files.
|
||||
const exporter = new gd.Exporter(fs, '/fake-gdjs-root');
|
||||
const exportOptions = new gd.MapStringBoolean();
|
||||
expect(
|
||||
exporter.exportWholePixiProject(
|
||||
project,
|
||||
'/fake-export-dir',
|
||||
exportOptions
|
||||
)
|
||||
).toBe(true);
|
||||
exportOptions.delete();
|
||||
exporter.delete();
|
||||
|
||||
// Check the index.html contains the include files.
|
||||
expect(fs.writeToFile.mock.calls[2][0]).toBe('/fake-export-dir/index.html');
|
||||
expect(fs.writeToFile.mock.calls[2][1]).toContain('gd.js');
|
||||
expect(fs.writeToFile.mock.calls[2][1]).toContain('affinetransformation.js');
|
||||
expect(fs.writeToFile.mock.calls[2][1]).toContain('pixi-renderers/runtimescene-pixi-renderer.js');
|
||||
expect(fs.writeToFile.mock.calls[2][1]).toContain('data.js');
|
||||
|
||||
// Check the webmanifest was properly generated.
|
||||
expect(fs.writeToFile.mock.calls[1][0]).toBe('/fake-export-dir/manifest.webmanifest');
|
||||
expect(() => JSON.parse(fs.writeToFile.mock.calls[1][1])).not.toThrow();
|
||||
expect(JSON.parse(fs.writeToFile.mock.calls[1][1])).toEqual({
|
||||
"name": "My great project with spaces and \"quotes\"!",
|
||||
"short_name": "My great project with spaces and \"quotes\"!",
|
||||
"id": "com.example.gamename",
|
||||
"description": "A nice project\nwith line breaks in the description.",
|
||||
"orientation": "landscape",
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"background_color": "black",
|
||||
"categories": ["games", "entertainment"],
|
||||
"icons": []
|
||||
});
|
||||
});
|
||||
it('properly exports Cordova files', () => {
|
||||
// Create a simple project
|
||||
const project = gd.ProjectHelper.createNewGDJSProject();
|
||||
@@ -242,10 +302,15 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
const unsupportedCapabilityAction = new gd.Instruction();
|
||||
unsupportedCapabilityAction.setType('EnableEffect');
|
||||
unsupportedCapabilityAction.setParametersCount(3);
|
||||
unsupportedCapabilityAction.setParameter(0, 'MyFakeObjectWithUnsupportedCapability');
|
||||
unsupportedCapabilityAction.setParameter(
|
||||
0,
|
||||
'MyFakeObjectWithUnsupportedCapability'
|
||||
);
|
||||
unsupportedCapabilityAction.setParameter(1, '"MyEffect"');
|
||||
unsupportedCapabilityAction.setParameter(2, 'yes');
|
||||
gd.asStandardEvent(evt).getActions().insert(unsupportedCapabilityAction, 4);
|
||||
gd.asStandardEvent(evt)
|
||||
.getActions()
|
||||
.insert(unsupportedCapabilityAction, 4);
|
||||
|
||||
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
|
||||
const code = layoutCodeGenerator.generateLayoutCompleteCode(
|
||||
@@ -269,7 +334,9 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
expect(code).toMatch('/* Unknown instruction - skipped. */');
|
||||
|
||||
// Check that the action for an object not having the required capability was not generated.
|
||||
expect(code).toMatch('/* Object with unsupported capability - skipped. */');
|
||||
expect(code).toMatch(
|
||||
'/* Object with unsupported capability - skipped. */'
|
||||
);
|
||||
|
||||
action.delete();
|
||||
});
|
||||
@@ -306,7 +373,9 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
unsupportedCapabilityAction.setParameter(0, 'MyGroup');
|
||||
unsupportedCapabilityAction.setParameter(1, '"MyEffect"');
|
||||
unsupportedCapabilityAction.setParameter(2, 'yes');
|
||||
gd.asStandardEvent(evt).getActions().insert(unsupportedCapabilityAction, 1);
|
||||
gd.asStandardEvent(evt)
|
||||
.getActions()
|
||||
.insert(unsupportedCapabilityAction, 1);
|
||||
|
||||
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
|
||||
const code = layoutCodeGenerator.generateLayoutCompleteCode(
|
||||
@@ -329,7 +398,9 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
expect(code).toMatch(
|
||||
'gdjs.SceneCode.GDMySpriteObjects1[i].enableEffect("MyEffect", true);'
|
||||
);
|
||||
expect(code).toMatch('/* Object with unsupported capability - skipped. */');
|
||||
expect(code).toMatch(
|
||||
'/* Object with unsupported capability - skipped. */'
|
||||
);
|
||||
|
||||
action.delete();
|
||||
});
|
||||
|
Reference in New Issue
Block a user