-
Notifications
You must be signed in to change notification settings - Fork 587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Teacher tool: first pass of nested validators #9862
Changes from 7 commits
aadd05b
645ef68
7990b8c
4125864
95d6aff
318c70d
d6149e4
40ed005
7bc28cc
4affb3a
9013578
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,33 +5,48 @@ import { validateBlocksInSetExist } from "./validateBlocksInSetExist"; | |
import { validateBlockCommentsExist } from "./validateCommentsExist"; | ||
import { validateSpecificBlockCommentsExist } from "./validateSpecificBlockCommentsExist"; | ||
|
||
const maxConcurrentChecks = 4; | ||
|
||
export async function runValidatorPlanAsync(usedBlocks: Blockly.Block[], plan: pxt.blocks.ValidatorPlan): Promise<boolean> { | ||
// Each plan can have multiple checks it needs to run. | ||
// Run all of them in parallel, and then check if the number of successes is greater than the specified threshold. | ||
// TBD if it's faster to run in parallel without short-circuiting once the threshold is reached, or if it's faster to run sequentially and short-circuit. | ||
export function runValidatorPlanAsync(usedBlocks: Blockly.Block[], plan: pxt.blocks.ValidatorPlan, planBank: pxt.blocks.ValidatorPlan[]): boolean { | ||
const startTime = Date.now(); | ||
let checksSucceeded = 0; | ||
let successfulBlocks: Blockly.Block[] = []; | ||
|
||
const checkRuns = pxt.Util.promisePoolAsync(maxConcurrentChecks, plan.checks, async (check: pxt.blocks.ValidatorCheckBase): Promise<boolean> => { | ||
for (const check of plan.checks) { | ||
let checkPassed = false; | ||
switch (check.validator) { | ||
case "blocksExist": | ||
return runBlocksExistValidation(usedBlocks, check as pxt.blocks.BlocksExistValidatorCheck); | ||
[successfulBlocks, checkPassed] = [...runBlocksExistValidation(usedBlocks, check as pxt.blocks.BlocksExistValidatorCheck)]; | ||
break; | ||
case "blockCommentsExist": | ||
return runValidateBlockCommentsExist(usedBlocks, check as pxt.blocks.BlockCommentsExistValidatorCheck); | ||
checkPassed = runValidateBlockCommentsExist(usedBlocks, check as pxt.blocks.BlockCommentsExistValidatorCheck); | ||
break; | ||
case "specificBlockCommentsExist": | ||
return runValidateSpecificBlockCommentsExist(usedBlocks, check as pxt.blocks.SpecificBlockCommentsExistValidatorCheck); | ||
checkPassed = runValidateSpecificBlockCommentsExist(usedBlocks, check as pxt.blocks.SpecificBlockCommentsExistValidatorCheck); | ||
break; | ||
case "blocksInSetExist": | ||
return runBlocksInSetExistValidation(usedBlocks, check as pxt.blocks.BlocksInSetExistValidatorCheck); | ||
[successfulBlocks, checkPassed] = [...runBlocksInSetExistValidation(usedBlocks, check as pxt.blocks.BlocksInSetExistValidatorCheck)]; | ||
break; | ||
default: | ||
pxt.debug(`Unrecognized validator: ${check.validator}`); | ||
return false; | ||
checkPassed = false; | ||
break; | ||
} | ||
}); | ||
|
||
const results = await checkRuns; | ||
const successCount = results.filter((r) => r).length; | ||
const passed = successCount >= plan.threshold; | ||
if (checkPassed && check.childValidatorPlans) { | ||
for (const planName of check.childValidatorPlans) { | ||
let timesPassed = 0; | ||
for (const parentBlock of successfulBlocks) { | ||
const blocksToUse = parentBlock.getChildren(true); | ||
const childPlan = planBank.find((plan) => plan.name === planName); | ||
const childPassed = runValidatorPlanAsync(blocksToUse, childPlan, planBank); | ||
timesPassed += childPassed ? 1 : 0; | ||
} | ||
checkPassed = timesPassed > 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential bug here. In the course of iterating over child validator plans, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, good catch. I think "anding" this will do the trick.. If we have any of the children validators fail, then the whole validator plan should fail, so, if at any moment, |
||
} | ||
} | ||
checksSucceeded += checkPassed ? 1 : 0; | ||
} | ||
|
||
const passed = checksSucceeded >= plan.threshold; | ||
|
||
pxt.tickEvent("validation.evaluation_complete", { | ||
plan: plan.name, | ||
|
@@ -42,13 +57,11 @@ export async function runValidatorPlanAsync(usedBlocks: Blockly.Block[], plan: p | |
return passed; | ||
} | ||
|
||
function runBlocksExistValidation(usedBlocks: Blockly.Block[], inputs: pxt.blocks.BlocksExistValidatorCheck): boolean { | ||
function runBlocksExistValidation(usedBlocks: Blockly.Block[], inputs: pxt.blocks.BlocksExistValidatorCheck): [Blockly.Block[], boolean] { | ||
const blockResults = validateBlocksExist({ usedBlocks, requiredBlockCounts: inputs.blockCounts }); | ||
const success = | ||
blockResults.disabledBlocks.length === 0 && | ||
blockResults.missingBlocks.length === 0 && | ||
blockResults.insufficientBlocks.length === 0; | ||
return success; | ||
const blockId = Object.keys(inputs.blockCounts)[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method has several array accesses without range checks. Are these arrays guaranteed to be non-empty? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For So, for example, if you have this validator:
The block that we're actually wanting to check for is |
||
const successfulBlocks = blockResults.successfulBlocks.length ? blockResults.successfulBlocks[0][blockId] : []; | ||
return [successfulBlocks, blockResults.passed]; | ||
} | ||
|
||
function runValidateBlockCommentsExist(usedBlocks: Blockly.Block[], inputs: pxt.blocks.BlockCommentsExistValidatorCheck): boolean { | ||
|
@@ -61,7 +74,7 @@ function runValidateSpecificBlockCommentsExist(usedBlocks: Blockly.Block[], inpu | |
return blockResults.passed; | ||
} | ||
|
||
function runBlocksInSetExistValidation(usedBlocks: Blockly.Block[], inputs: pxt.blocks.BlocksInSetExistValidatorCheck): boolean { | ||
function runBlocksInSetExistValidation(usedBlocks: Blockly.Block[], inputs: pxt.blocks.BlocksInSetExistValidatorCheck): [Blockly.Block[], boolean] { | ||
const blockResults = validateBlocksInSetExist({ usedBlocks, blockIdsToCheck: inputs.blocks, count: inputs.count }); | ||
return blockResults.passed; | ||
return [blockResults.successfulBlocks, blockResults.passed]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small naming suggestion for clarity.