Skip to content

Commit 4e093f2

Browse files
authored
Merge pull request code-dot-org#24634 from code-dot-org/auto-artist
Fix a couple auto artist bugs
2 parents 37f47d4 + bfca7e2 commit 4e093f2

File tree

8 files changed

+95
-19
lines changed

8 files changed

+95
-19
lines changed

apps/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@cdo/apps": "file:src",
4141
"@cdo/interpreted": "link:../dashboard/config/libraries",
4242
"@code-dot-org/artist": "0.2.1",
43-
"@code-dot-org/blockly": "3.1.1",
43+
"@code-dot-org/blockly": "3.1.3",
4444
"@code-dot-org/bramble": "0.1.26",
4545
"@code-dot-org/craft": "0.1.5",
4646
"@code-dot-org/johnny-five": "0.11.1-cdo.2",

apps/src/lib/tools/jsinterpreter/CustomMarshalingInterpreter.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ const Interpreter = require('@code-dot-org/js-interpreter');
44
const CustomMarshaler = require('./CustomMarshaler');
55

66
const DEFAULT_MAX_STEPS = 5e5;
7-
8-
const defaultExecutionInfo = {
7+
export const DEFAULT_EXECUTION_INFO = {
98
ticks: DEFAULT_MAX_STEPS,
109
checkTimeout: function () {
1110
if (this.ticks-- < 0) {
12-
throw 'Infinity';
11+
throw new Error('Infinity');
1312
}
1413
},
1514
isTerminated: () => false,
@@ -33,7 +32,7 @@ function isCanvasImageData(nativeVar) {
3332
return nativeVar instanceof CanvasPixelArray;
3433
}
3534

36-
module.exports = class CustomMarshalingInterpreter extends Interpreter {
35+
export default class CustomMarshalingInterpreter extends Interpreter {
3736
constructor(code, customMarshaler, opt_initFunc) {
3837
super(code, (thisInterpreter, scope) => {
3938
if (!(customMarshaler instanceof CustomMarshaler)) {
@@ -411,7 +410,7 @@ module.exports = class CustomMarshalingInterpreter extends Interpreter {
411410
let interpreter, currentCallback, lastReturnValue;
412411
const hooks = [];
413412
const apis = {
414-
executionInfo: defaultExecutionInfo,
413+
executionInfo: DEFAULT_EXECUTION_INFO,
415414
...scope,
416415
};
417416

@@ -588,7 +587,7 @@ module.exports = class CustomMarshalingInterpreter extends Interpreter {
588587
*/
589588
static evalWith(code, scope, {asyncFunctionList, legacy}={}) {
590589
const globals = {
591-
executionInfo: defaultExecutionInfo,
590+
executionInfo: DEFAULT_EXECUTION_INFO,
592591
...scope,
593592
};
594593

@@ -806,5 +805,4 @@ module.exports = class CustomMarshalingInterpreter extends Interpreter {
806805
);
807806
};
808807
}
809-
810-
};
808+
}

apps/src/maze/maze.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const Provider = require('react-redux').Provider;
44

55
const timeoutList = require('../lib/util/timeoutList');
66
import AppView from '../templates/AppView';
7-
const CustomMarshalingInterpreter = require('../lib/tools/jsinterpreter/CustomMarshalingInterpreter');
7+
const CustomMarshalingInterpreter = require('../lib/tools/jsinterpreter/CustomMarshalingInterpreter').default;
88
const codegen = require('../lib/tools/jsinterpreter/codegen');
99
const dom = require('../dom');
1010
const utils = require('../utils');

apps/src/turtle/artist.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {SignInState} from '../code-studio/progressRedux';
5757
import Visualization from '@code-dot-org/artist';
5858
import experiments from '../util/experiments';
5959
import {ArtistAutorunOptions} from '@cdo/apps/util/sharedConstants';
60+
import {DEFAULT_EXECUTION_INFO} from '@cdo/apps/lib/tools/jsinterpreter/CustomMarshalingInterpreter';
6061

6162
const CANVAS_HEIGHT = 400;
6263
const CANVAS_WIDTH = 400;
@@ -181,8 +182,6 @@ var Artist = function () {
181182

182183
// these get set by init based on skin.
183184
this.speedSlider = null;
184-
185-
this.immovableBlocks = [];
186185
};
187186

188187
module.exports = Artist;
@@ -305,6 +304,11 @@ Artist.prototype.init = function (config) {
305304
this.level.autoRun === ArtistAutorunOptions.limited_auto_run;
306305
this.autoRun = experiments.isEnabled('auto-artist') || this.level.autoRun;
307306

307+
this.executionInfo = { ...DEFAULT_EXECUTION_INFO };
308+
if (this.level.maxTickCount !== undefined) {
309+
this.executionInfo.ticks = this.level.maxTickCount;
310+
}
311+
308312
config.grayOutUndeletableBlocks = true;
309313
config.forceInsertTopBlock = 'when_run';
310314
config.dropletConfig = dropletConfig;
@@ -726,23 +730,29 @@ Artist.prototype.resetButtonClick = function () {
726730
}
727731
};
728732

729-
Artist.prototype.evalCode = function (code) {
733+
Artist.prototype.evalCode = function (code, executionInfo=this.executionInfo) {
730734
try {
731735
CustomMarshalingInterpreter.evalWith(code, {
732-
Turtle: this.api
736+
Turtle: this.api,
737+
// The default executionInfo modifies itself, make a fresh copy each run
738+
executionInfo: {
739+
...executionInfo,
740+
},
733741
});
734742
} catch (e) {
735743
// Infinity is thrown if we detect an infinite loop. In that case we'll
736744
// stop further execution, animate what occurred before the infinite loop,
737745
// and analyze success/failure based on what was drawn.
738746
// Otherwise, abnormal termination is a user error.
739-
if (e !== 'Infinity') {
747+
if (e.message !== 'Infinity') {
740748
// call window.onerror so that we get new relic collection. prepend with
741749
// UserCode so that it's clear this is in eval'ed code.
742750
if (window.onerror) {
743751
window.onerror("UserCode:" + e.message, document.URL, 0);
744752
}
745-
window.alert(e);
753+
if (this.shouldAnimate_) {
754+
window.alert(e);
755+
}
746756
}
747757
}
748758
};

apps/test/integration/levelSolutions/turtle/5_5.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,55 @@ module.exports = {
5050
' </next>' +
5151
' </block>' +
5252
'</xml>'
53+
},
54+
{
55+
description: "Free play level with more ticks than allowed",
56+
expected: {
57+
result: true,
58+
testResult: TestResults.FREE_PLAY
59+
},
60+
runBeforeClick: function () {
61+
// This is a free-play level: click Finish when drawing is done.
62+
addEventListener('artistDrawingComplete', () => $('#finishButton').click());
63+
},
64+
levelDefinitionOverrides: {
65+
maxTickCount: 10,
66+
},
67+
xml:
68+
'<xml>' +
69+
' <block type="when_run" deletable="false" movable="false">' +
70+
' <next>' +
71+
' <block type="controls_for_counter" inline="true">' +
72+
' <mutation counter="counter"></mutation>' +
73+
' <value name="FROM">' +
74+
' <block type="math_number">' +
75+
' <title name="NUM">1</title>' +
76+
' </block>' +
77+
' </value>' +
78+
' <value name="TO">' +
79+
' <block type="math_number">' +
80+
' <title name="NUM">1000000</title>' +
81+
' </block>' +
82+
' </value>' +
83+
' <value name="BY">' +
84+
' <block type="math_number">' +
85+
' <title name="NUM">1</title>' +
86+
' </block>' +
87+
' </value>' +
88+
' <statement name="DO">' +
89+
' <block type="draw_move" inline="true">' +
90+
' <title name="DIR">moveForward</title>' +
91+
' <value name="VALUE">' +
92+
' <block type="math_number">' +
93+
' <title name="NUM">0</title>' +
94+
' </block>' +
95+
' </value>' +
96+
' </block>' +
97+
' </statement>' +
98+
' </block>' +
99+
' </next>' +
100+
' </block>' +
101+
'</xml>'
53102
}
54103
]
55104
};

apps/test/integration/util/testCollectionUtils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ module.exports = {
5757
if (testCollection.levelFile) {
5858
var levels = data.levels[testCollection.levelFile];
5959
level = _.cloneDeep(levels[testCollection.levelId]);
60+
level = {
61+
...level,
62+
...(testData.levelDefinitionOverrides || {}),
63+
};
6064
} else {
6165
if (!testCollection.levelDefinition && !testData.delayLoadLevelDefinition) {
6266
logError('testCollection requires levelFile or levelDefinition');

apps/test/unit/turtle/turtleTest.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {expect} from '../../util/configuredChai';
33
import {parseElement} from '@cdo/apps/xml';
44
import {Position} from '@cdo/apps/constants';
55
import {singleton as studioAppSingleton} from '@cdo/apps/StudioApp';
6+
import {DEFAULT_EXECUTION_INFO} from '@cdo/apps/lib/tools/jsinterpreter/CustomMarshalingInterpreter';
67
const Artist = require('@cdo/apps/turtle/artist');
78

89
const SHORT_DIAGONAL = 50 * Math.sqrt(2);
@@ -400,4 +401,18 @@ describe('Artist', () => {
400401
expect(newDom.querySelector('block[type="when_run"]')).to.be.defined;
401402
});
402403
});
404+
405+
it('Does not alert for infinite loops', () => {
406+
const artist = new Artist();
407+
const alertStub = sinon.stub(window, 'alert');
408+
409+
artist.evalCode('while(true) executionInfo.checkTimeout();', {
410+
...DEFAULT_EXECUTION_INFO,
411+
ticks: 10, // Declare an infinite loop after 10 ticks
412+
});
413+
414+
expect(alertStub).to.not.have.been.called;
415+
416+
alertStub.restore();
417+
});
403418
});

apps/yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
version "0.2.1"
1414
resolved "https://registry.yarnpkg.com/@code-dot-org/artist/-/artist-0.2.1.tgz#fcfe7ea5cfb3f19ddb6b912e70e922ba4b7ef0b1"
1515

16-
"@code-dot-org/[email protected].1":
17-
version "3.1.1"
18-
resolved "https://registry.yarnpkg.com/@code-dot-org/blockly/-/blockly-3.1.%3Cspan%20class="x x-first x-last">1.tgz#9ffe14124c4064fcd97a1bb5b0eca7232d478372"
16+
"@code-dot-org/[email protected].3":
17+
version "3.1.3"
18+
resolved "https://registry.yarnpkg.com/@code-dot-org/blockly/-/blockly-3.1.%3Cspan%20class="x x-first x-last">3.tgz#4ea81a4dd5bc542d831b4312ccdf0255a4234239"
1919

2020
"@code-dot-org/[email protected]":
2121
version "0.1.26"

0 commit comments

Comments
 (0)