Package org.openquark.gems.client

Source Code of org.openquark.gems.client.Autoburn_Test

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* Autoburn_Test.java
* Created: Jan 14, 2005
* By: Peter Cardwell
*/

package org.openquark.gems.client;

import java.util.Arrays;
import java.util.HashSet;

import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.openquark.cal.CALPlatformTestModuleNames;
import org.openquark.cal.compiler.CodeAnalyser;
import org.openquark.cal.compiler.MessageLogger;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.TypeException;
import org.openquark.cal.compiler.TypeExpr;
import org.openquark.cal.module.Cal.Collections.CAL_List;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.services.BasicCALServices;
import org.openquark.cal.services.GemEntity;
import org.openquark.gems.client.AutoburnLogic.AutoburnInfo;


/**
* Tests various uses of AutoburnLogic.getAutoburnInfo().
* @author Peter Cardwell
*/
public class Autoburn_Test extends TestCase {
   
    static BasicCALServices calServices;
    private static final ModuleName testModule = CALPlatformTestModuleNames.M2;
   
    public Autoburn_Test(String name) {
        super(name);
    }
   
    public Autoburn_Test() {
        super("");
    }

    /**
     * Tests the version of getAutoburnInfo() that takes an array of TypeExpr objects.
     */
    public void testSimpleAutoburn() {

        // Make the source a function of type a -> b -> c, and the destination a gem of type a -> b
        TypeExpr[] sourceTypes = new TypeExpr[] {
            TypeExpr.makeParametricType()// first argument
            TypeExpr.makeParametricType()// second argument
            TypeExpr.makeParametricType()   // output type
        };
        TypeExpr destType = calServices.getTypeFromString(testModule, "a -> b");
       
        AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destType, sourceTypes, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.AMBIGUOUS_NOT_NECESSARY, autoburnInfo.getAutoburnUnifyStatus());
       
        // Every possible burn combination is valid here, ie leaving both arguments unburned,
        // burning either argument, or burning both arguments.
        assertEquals(3, autoburnInfo.getBurnCombinations().size());       
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(argsToBurn, new int[] {0}));
        argsToBurn = (autoburnInfo.getBurnCombinations().get(1)).getInputsToBurn();
        assertTrue(Arrays.equals(argsToBurn, new int[] {1}));
        argsToBurn = (autoburnInfo.getBurnCombinations().get(2)).getInputsToBurn();
        assertTrue(Arrays.equals(argsToBurn, new int[] {0, 1}));
    }
   
    /**
     * Tests the version of getAutoburnInfo() that takes an array of TypeExpr objects,
     * in the case where burning should not be necessary.
     */
    public void testSimpleAutoburnNotNecessary() {

        // Make the source a function of type a -> b, and the destination a gem of type [a].
        TypeExpr[] sourceTypes = new TypeExpr[] {           
            TypeExpr.makeParametricType()// second argument
            TypeExpr.makeParametricType()   // output type
        };
        TypeExpr destType = calServices.getTypeFromString(testModule, "[a]");
       
        AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destType, sourceTypes, calServices.getTypeCheckInfo(testModule));

        // The only possibility here is to leave the argument unburned.
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.NOT_NECESSARY, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(0, autoburnInfo.getBurnCombinations().size());      
    }
   
    /**
     * Tests the version of getAutoburnInfo() that takes a gem entity.
     */
    public void testAutoburnGemEntity() {
       
        // We'll use List.map for the source entity and [a] -> [b] for the destination
        GemEntity gemEntity = calServices.getCALWorkspace().getGemEntity(CAL_List.Functions.map);
        TypeExpr destType = calServices.getTypeFromString(testModule, "[a] -> [b]");
       
        AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destType, gemEntity, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
       
        // The only way to connect these two types together is by burning the second argument.
        assertEquals(1, autoburnInfo.getBurnCombinations().size());       
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(argsToBurn, new int[] {1}));
    }   
   
    /**
     * Tests getAutoburnInfo() with a two-argument gem where both of the arguments are unburnt.
     */
    public void testAutoburnDualArgGemBothArgsUnburnt() {
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                                                     calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                                                     true,
                                                     false);
       
        // Create the source gem       
        // Output type: Boolean, Input types: Double, Boolean
        String code = "let x = (a :: " + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", b :: " + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + "); in " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem sourceGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Create the destination gem
        // Input type: Double -> Boolean -> a, Output type: a
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem destGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // It should be necessary to burn both inputs of the source gem
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destGem.getInputPart(0).getType(), sourceGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(1, autoburnInfo.getBurnCombinations().size());
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(new int[] {0, 1}, argsToBurn));
    }

    /**
     * Tests getAutoburnInfo() with a two-argument gem where the first argument is pre-burnt.
     */
    public void testAutoburnDualArgGemFirstArgBurnt() {
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                                                     calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                                                     true,
                                                     false);
       
        GemGraph gemGraph = new GemGraph();
       
        // Create the source gem       
        // Output type: Boolean, Input types: Double, Boolean
        String code = "let x = (a :: " + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", b :: " + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + "); in " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem sourceGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(sourceGem);
       
        // Create the destination gem
        // Input type: Double -> Boolean -> a, Output type: a
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem destGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(destGem);
       
        // Now burn the first input of the gem
        sourceGem.getInputPart(0).setBurnt(true);
        try {
            gemGraph.typeGemGraph(calServices.getTypeCheckInfo(testModule));
        } catch (TypeException e) {
            throw new Error("Error typing gem graph");
        }
       
        // It should be necessary to burn both inputs of the source gem
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destGem.getInputPart(0).getType(), sourceGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(1, autoburnInfo.getBurnCombinations().size());
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(new int[] {1}, argsToBurn));
    }

    /**
     * Tests getAutoburnInfo() with a two-argument gem where the second argument is pre-burnt.
     */
    public void testAutoburnDualArgGemSecondArgBurnt() {
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                                                     calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                                                     true,
                                                     false);
       
        GemGraph gemGraph = new GemGraph();
        // Create the source gem       
        // Output type: Boolean, Input types: Double, Boolean
        String code = "let x = (a :: " + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", b :: " + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + "); in " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem sourceGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(sourceGem);
       
        // Create the destination gem
        // Input type: Double -> Boolean -> a, Output type: a
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem destGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(destGem);
       
       
        // Now burn the first input of the gem
        sourceGem.getInputPart(1).setBurnt(true);
        try {
            gemGraph.typeGemGraph(calServices.getTypeCheckInfo(testModule));
        } catch (TypeException e) {
            throw new Error("Error typing gem graph");
        }
       
        // It should be necessary to burn both inputs of the source gem
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destGem.getInputPart(0).getType(), sourceGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(1, autoburnInfo.getBurnCombinations().size());
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(new int[] {0}, argsToBurn));
    }

    /**
     * Tests getAutoburnInfo() with a two-argument gem where both arguments are pre-burnt.
     */
    public void testAutoburnDualArgGemBothArgsBurnt() {
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                                                     calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                                                     true,
                                                     false);

        GemGraph gemGraph = new GemGraph();
       
        // Create the source gem       
        // Output type: Boolean, Input types: Double, Boolean
        String code = "let x = (a :: " + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", b :: " + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + "); in " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem sourceGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(sourceGem);
       
        // Create the destination gem
        // Input type: Double -> Boolean -> a, Output type: a
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem destGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(destGem);
       
        // Now burn both inputs of the gem
        sourceGem.getInputPart(0).setBurnt(true);
        sourceGem.getInputPart(1).setBurnt(true);
        try {
            gemGraph.typeGemGraph(calServices.getTypeCheckInfo(testModule));
        } catch (TypeException e) {
            throw new Error("Error typing gem graph");
        }
       
        // It should be necessary to burn both inputs of the source gem
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destGem.getInputPart(0).getType(), sourceGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.NOT_NECESSARY, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(0, autoburnInfo.getBurnCombinations().size());
    }

    /**
     * Test autoburning of a gem that has a bound connection.
     */
    public void testAutoburnBoundGem() {
        // Create a new code analyser so we can build code gems
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                                                     calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                                                     true,
                                                     false);
       
        // Create the code gem that will be bound to the primary source gem.
        String code = "(firstSecondaryArg, secondSecondaryArg)";
        Gem secondaryCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Create the code gem that will act as the source gem for the autoburn query.
        code = "(firstPrimaryArg::" + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", secondPrimaryArg, thirdPrimaryArg::" + CAL_Prelude.TypeConstructors.Int.getQualifiedName() + ", fourth::" + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + ", fifth::" + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + ")";
        CodeGem primaryCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Create the code gem that will act as the destination gem for the autoburn query.
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName() + " " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem destinationCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Connect secondaryCodeGem to first input of primaryCodeGem
        Connection connection = new Connection(secondaryCodeGem.getOutputPart(), primaryCodeGem.getInputPart(1));
        primaryCodeGem.getInputPart(1).bindConnection(connection);
        secondaryCodeGem.getOutputPart().bindConnection(connection);
               
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destinationCodeGem.getInputPart(0).getType(), primaryCodeGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(1, autoburnInfo.getBurnCombinations().size());
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(new int[] {0, 3, 4}, argsToBurn));
    }
   
    /**
     * Test autoburning of a gem that has a bound connection and one of it's inputs already burnt.
     */
    public void testAutoburnBoundAndBurntGem() {
        //Create a new code analyser so we can build code gems
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
            calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
            true,
            false);
        GemGraph gemGraph = new GemGraph();
       
        String code = "(firstSecondaryArg, secondSecondaryArg)";
        Gem secondaryCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(secondaryCodeGem);
       
        code = "(firstPrimaryArg::" + CAL_Prelude.TypeConstructors.Double.getQualifiedName() + ", secondPrimaryArg, thirdPrimaryArg::" + CAL_Prelude.TypeConstructors.Int.getQualifiedName() + ", fourth::" + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + ", fifth::" + CAL_Prelude.TypeConstructors.Boolean.getQualifiedName() + ")";
        CodeGem primaryCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(primaryCodeGem);
       
        code = "f 1.0 " + CAL_Prelude.DataConstructors.True.getQualifiedName() + " " + CAL_Prelude.DataConstructors.True.getQualifiedName();
        Gem outputCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
        gemGraph.addGem(outputCodeGem);
       
        // Connect secondaryCodeGem to second input of primaryCodeGem
        Connection connection = new Connection(secondaryCodeGem.getOutputPart(), primaryCodeGem.getInputPart(1));
        primaryCodeGem.getInputPart(1).bindConnection(connection);
        secondaryCodeGem.getOutputPart().bindConnection(connection);
               
        // Burn the fourth input to the primary code gem, and re-set the output type appropriately
        primaryCodeGem.getInputPart(3).setBurnt(true);
        try {
            gemGraph.typeGemGraph(calServices.getTypeCheckInfo(testModule));
        } catch (TypeException e) {
            throw new Error("Error typing gem graph");
        }
       
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(outputCodeGem.getInputPart(0).getType(), primaryCodeGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(1, autoburnInfo.getBurnCombinations().size());
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(new int[] {0, 4}, argsToBurn));
    }
   
    /**
     * Tests autoburning on a code gem that outputs a function even before any arguments are burnt.
     */
    public void testAutoburnFunctionGem() {
        // Create a new code analyzer so we can build code gems
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                true,
                false);
       
        // Create a gem whose output type is Num a => [a] -> [a]
        String code = CAL_List.Functions.map.getQualifiedName() + " (\\ x -> x + 1)";
        Gem functionCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Create another gem whose input is of type Num c => [c] -> b
        code = "f [1, 2]";
        Gem destinationCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // These gems should be able to connect without having to do any autoburning
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destinationCodeGem.getInputPart(0).getType(), functionCodeGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(AutoburnLogic.AutoburnUnifyStatus.NOT_NECESSARY, autoburnInfo.getAutoburnUnifyStatus());
        assertEquals(autoburnInfo.getBurnCombinations().size(), 0);       
    }
   
    /**
     * Second test autoburning a code gem that outputs a function even before any arguments are burnt.
     * In this case, the test is designed so that burning the input is necessary.
     */
    public void testAutoburnFunctionGem2() {
        // Create a new code analyser so we can build code gems
        CodeAnalyser codeAnalyser = new CodeAnalyser(calServices.getTypeChecker(),
                calServices.getCALWorkspace().getMetaModule(testModule).getTypeInfo(),
                true,
                false);
       
        // Create a gem with output type Num b => [b] -> [b] and input type a
        String code = "let y = a; in " + CAL_List.Functions.map.getQualifiedName() + " (\\x -> x + 1)";
        Gem functionCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // Create a gem whose first input is of type Num e => c -> [e] -> d
        code = "f b [1, 2]";
        Gem destinationCodeGem = new CodeGem(codeAnalyser, code, new HashSet<String>());
       
        // In order to connect these gems, we would need to burn the first input. Let's make sure the autoBurner agrees.
        AutoburnLogic.AutoburnInfo autoburnInfo = AutoburnLogic.getAutoburnInfo(destinationCodeGem.getInputPart(0).getType(), functionCodeGem, calServices.getTypeCheckInfo(testModule));
        assertEquals(autoburnInfo.getAutoburnUnifyStatus(), AutoburnLogic.AutoburnUnifyStatus.UNAMBIGUOUS);
        assertEquals(autoburnInfo.getBurnCombinations().size(), 1);       
        int[] argsToBurn = (autoburnInfo.getBurnCombinations().get(0)).getInputsToBurn();
        assertTrue(Arrays.equals(argsToBurn, new int[] {0}));
       
    }
   
    public static Test suite() {

        TestSuite suite = new TestSuite(Autoburn_Test.class);

        return new TestSetup(suite) {

            @Override
            protected void setUp() {
                oneTimeSetUp();
               
            }
   
            @Override
            protected void tearDown() {
                oneTimeTearDown();
            }
        };
    }
   
    public static void oneTimeSetUp() {
        calServices = BasicCALServices.make(GemCutter.GEMCUTTER_PROP_WORKSPACE_FILE, "cal.platform.test.cws", null);
        calServices.compileWorkspace(null, new MessageLogger());
    }
   
    public static void oneTimeTearDown() {
        calServices = null;
    }
   
}
TOP

Related Classes of org.openquark.gems.client.Autoburn_Test

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.