DonateLiveCodeTransformation extends DonateCodeTransformation { @Override public String getName() { return NAME; } DonateLiveCodeTransformation(Function<IRandom, Boolean> probabilityOfDonation,
                                      File donorsDirectory,
                                      GenerationParams generationParams,
                                      boolean allowLongLoops); @Override String getName(); static final String NAME; }
@Test public void testArrayAccessesAreInBounds() throws Exception { final ShaderJobFileOperations fileOps = new ShaderJobFileOperations(); final File donors = testFolder.newFolder("donors"); final File referenceFile = testFolder.newFile("reference.json"); { final String donorSource = "#version 300 es\n" + "void main() {\n" + " int x = 0;\n" + " {\n" + " int A[1];\n" + " A[x] = 42;\n" + " {\n" + " int B[1];\n" + " B[x] = 42;\n" + " {\n" + " int C[1];\n" + " C[x] = 42;\n" + " }\n" + " }\n" + " }\n" + "}\n"; fileOps.writeShaderJobFileFromImageJob( new ImageJob() .setFragmentSource(donorSource) .setUniformsInfo("{}"), new File(donors, "donor.json") ); } { final String referenceSource = "#version 300 es\n" + "void main() {\n" + "}\n"; fileOps.writeShaderJobFileFromImageJob( new ImageJob() .setFragmentSource(referenceSource) .setUniformsInfo("{}"), referenceFile ); } int noCodeDonatedCount = 0; for (int seed = 0; seed < 15; seed++) { final ShaderJob referenceShaderJob = fileOps.readShaderJobFile(referenceFile); DonateLiveCodeTransformation transformation = new DonateLiveCodeTransformation(IRandom::nextBoolean, donors, GenerationParams.normal(ShaderKind.FRAGMENT, true), false); assert referenceShaderJob.getFragmentShader().isPresent(); boolean result = transformation.apply( referenceShaderJob.getFragmentShader().get(), TransformationProbabilities.onlyLiveCodeAlwaysSubstitute(), new RandomWrapper(seed), GenerationParams.normal(ShaderKind.FRAGMENT, true) ); if (!result) { ++noCodeDonatedCount; continue; } new ScopeTrackingVisitor() { @Override public void visitArrayIndexExpr(ArrayIndexExpr arrayIndexExpr) { super.visitArrayIndexExpr(arrayIndexExpr); if (arrayIndexExpr.getIndex() instanceof VariableIdentifierExpr) { final ScopeEntry scopeEntry = getCurrentScope().lookupScopeEntry( ((VariableIdentifierExpr) arrayIndexExpr.getIndex()).getName()); assertTrue(scopeEntry.hasVariableDeclInfo()); assertNotNull(scopeEntry.getVariableDeclInfo().getInitializer()); assertFalse((scopeEntry.getVariableDeclInfo().getInitializer()) .getExpr() instanceof FunctionCallExpr); } } }.visit(referenceShaderJob.getFragmentShader().get()); } Assert.assertTrue( "Donation failure count should be < 10, " + noCodeDonatedCount, noCodeDonatedCount < 10 ); }