/*
* 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.
*/
/*
* LocalPatternMatch_Test.java
* Created: Mar 22, 2007
* By: JoWong
*/
package org.openquark.cal.compiler;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.openquark.cal.runtime.MachineType;
import org.openquark.cal.services.BasicCALServices;
import org.openquark.cal.services.CALServicesTestUtilities;
/**
* A set of time-consuming JUnit test cases for the local pattern match syntax.
*
* @author Joseph Wong
*/
public class LocalPatternMatch_Test extends TestCase {
/**
* A copy of CAL services for use in the test cases.
*/
private static BasicCALServices leccCALServices;
/**
* Set this flag to true if debugging output is desired regardless of
* whether a test fails or succeeds.
*/
private static final boolean SHOW_DEBUGGING_OUTPUT = false;
/**
* @return a test suite containing all the test cases for testing CAL source
* generation.
*/
public static Test suite() {
TestSuite suite = new TestSuite(LocalPatternMatch_Test.class);
return new TestSetup(suite) {
@Override
protected void setUp() {
oneTimeSetUp();
}
@Override
protected void tearDown() {
oneTimeTearDown();
}
};
}
/**
* Performs the setup for the test suite.
*/
private static void oneTimeSetUp() {
leccCALServices = CALServicesTestUtilities.getCommonCALServices(MachineType.LECC, "cal.platform.test.cws");
}
/**
* Performs the tear down for the test suite.
*/
private static void oneTimeTearDown() {
leccCALServices = null;
}
/**
* Tests the error message for when a local pattern match declaration is used with a multiple data consturctor pattern.
*/
public void testInvalidLocalPatternMatchMultipleDataConsPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (Prelude.Left|Prelude.Right) {value} = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchMultipleDataConsPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with an empty list [] pattern.
*/
public void testInvalidLocalPatternMatchNilPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let [] = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchNilPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a unit () pattern.
*/
public void testInvalidLocalPatternMatchUnitPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let () = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchUnitPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with an integer pattern.
*/
public void testInvalidLocalPatternMatchIntPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let 42 = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchIntPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let -42 = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchIntPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (-42|42) = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchIntPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a character pattern.
*/
public void testInvalidLocalPatternMatchCharPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let 'X' = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchCharPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let ('X'|'Y') = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchCharPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo17 = let 'c' 1 = 4; in 3;",
MessageKind.Error.InvalidLocalPatternMatchCharPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with just a wildcard pattern.
*/
public void testInvalidLocalPatternMatchWildcardPattern() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let _ = Prelude.undefined; in 3.0;",
MessageKind.Error.InvalidLocalPatternMatchWildcardPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a pattern that contains no pattern variables.
*/
public void testLocalPatternMatchDeclMustContainAtLeastOnePatternVar() {
// data cons pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Just {} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Just _ = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Just {value=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons _ _ = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons {head=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons {tail=_, head=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
// colon pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let _:_ = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
// tuple pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (_, _) = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (_, _, _, _, _) = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
// record pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {_|} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {_|a=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {a=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {#1=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {_|a=_, #1=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {a=_, #1=_} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
// punned ordinal fields become wildcards
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {#1} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {#1, #2} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclMustContainAtLeastOnePatternVar.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a base record pattern that is not the wildcard pattern.
*/
public void testNonWildcardBaseRecordPatternNotSupportedInLocalPatternMatchDecl() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {r|a} = Prelude.undefined; in 3.0;",
MessageKind.Error.NonWildcardBaseRecordPatternNotSupportedInLocalPatternMatchDecl.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {r|#1=x} = Prelude.undefined; in 3.0;",
MessageKind.Error.NonWildcardBaseRecordPatternNotSupportedInLocalPatternMatchDecl.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {r|a, #1=x} = Prelude.undefined; in 3.0;",
MessageKind.Error.NonWildcardBaseRecordPatternNotSupportedInLocalPatternMatchDecl.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a data constructor pattern with the wrong number of
* positional patterns.
*/
public void testConstructorMustHaveExactlyNArgsInLocalPatternMatchDecl() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Just = Prelude.undefined; in 3.0;",
MessageKind.Error.ConstructorMustHaveExactlyNArgsInLocalPatternMatchDecl.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons _ = Prelude.undefined; in 3.0;",
MessageKind.Error.ConstructorMustHaveExactlyNArgsInLocalPatternMatchDecl.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration is used with a data constructor pattern where the data constructor
* has an arity of 0.
*/
public void testConstructorMustHavePositiveArityInLocalPatternMatchDecl() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Nil = Prelude.undefined; in 3.0;",
MessageKind.Error.ConstructorMustHavePositiveArityInLocalPatternMatchDecl.class, leccCALServices);
}
/**
* Tests the error message for when a data constructor local pattern match declaration using matching notation attempts to bind a field which doesn't exist.
*/
public void testUnknownDataConstructorField() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo18 = let Prelude.Cons {foo} = [1]; in foo;",
MessageKind.Error.UnknownDataConstructorField.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration contains a binds a pattern variable more than once.
*/
public void testRepeatedVariableUsedInBinding() {
// data cons pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons x x = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedVariableUsedInBinding.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons {head=x, tail=x} = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedPatternVariableInFieldBindingPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons {head, tail=head} = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedVariableUsedInBinding.class, leccCALServices);
// colon pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let x:x = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedVariableUsedInBinding.class, leccCALServices);
// tuple pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (x, x) = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedVariableUsedInBinding.class, leccCALServices);
// record pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {x, y=x} = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedPatternVariableInFieldBindingPattern.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let {#3=x, y=x} = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedPatternVariableInFieldBindingPattern.class, leccCALServices);
}
/**
* Tests the error message for when a local pattern match declaration binds a pattern variable that is also defined
* elsewhere in the let declaration.
*/
public void testRepeatedDefinitionInLetDeclaration() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let (x, y) = Prelude.undefined; x = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedDefinitionInLetDeclaration.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let x = Prelude.undefined; (x, y) = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedDefinitionInLetDeclaration.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let x:z = Prelude.undefined; (x, y) = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedDefinitionInLetDeclaration.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let Prelude.Cons x z = Prelude.undefined; {x, y} = Prelude.undefined; in 3.0;",
MessageKind.Error.RepeatedDefinitionInLetDeclaration.class, leccCALServices);
}
/**
* Tests the error message for when the type of a local pattern-bound variable is not compatible with the defining expression of the local pattern match declaration.
*/
public void testTypeOfPatternBoundVariableNotCompatibleWithLocalPatternMatchDecl() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo2 = let a:b = [Prelude.fromJust b]; in a;",
MessageKind.Error.TypeOfPatternBoundVariableNotCompatibleWithLocalPatternMatchDecl.class, leccCALServices);
}
/**
* Tests the error message for when the type of the defining expression of the local pattern match declaration is not compatible with the type(s) of the corresponding pattern-bound variable(s).
*/
public void testTypeOfDesugaredDefnOfLocalPatternMatchDeclNotCompatibleWithPatternBoundVars() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo19 = let {ax, b2} = (b2, ax); in (ax, b2);",
MessageKind.Error.TypeOfDesugaredDefnOfLocalPatternMatchDeclNotCompatibleWithPatternBoundVars.class, leccCALServices);
}
/**
* Tests the error message for when the type the defining expression of this local pattern match declaration does not have all and only the declared fields.
*/
public void testLocalPatternMatchDeclMustHaveFields() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo6 = let {a} = {a = \"foo\", b = \"bar\"}; in a;",
MessageKind.Error.LocalPatternMatchDeclMustHaveFields.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo6a = let {x} = {a = \"foo\", b = \"bar\"}; in x;",
MessageKind.Error.LocalPatternMatchDeclMustHaveFields.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo7b = let {#1 = a} = ('a', 'b', 'c'); in a;",
MessageKind.Error.LocalPatternMatchDeclMustHaveFields.class, leccCALServices);
}
/**
* Tests the error message for when the type the defining expression of this local pattern match declaration does not have at least the declared fields.
*/
public void testLocalPatternMatchDeclMustAtLeastHaveFields() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo6x = let {_|#1,a} = {a = \"foo\"}; in a;",
MessageKind.Error.LocalPatternMatchDeclMustAtLeastHaveFields.class, leccCALServices);
}
/**
* Tests the error message for when the type of the defining expression of this local pattern match declaration is not a tuple type with the declared dimension.
*/
public void testLocalPatternMatchDeclMustHaveTupleDimension() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo7 = let (a, b) = ('a', 'b', 'c'); in a;",
MessageKind.Error.LocalPatternMatchDeclMustHaveTupleDimension.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo7a = let {#1 = a, #2 = b} = ('a', 'b', 'c'); in a;",
MessageKind.Error.LocalPatternMatchDeclMustHaveTupleDimension.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo7c = let (a, b, c, d) = ('a', 'b', 'c'); in a;",
MessageKind.Error.LocalPatternMatchDeclMustHaveTupleDimension.class, leccCALServices);
}
/**
* Tests the error message for when a field declared in a local pattern match declaration is missing from the type of the defining expression.
*/
public void testInvalidRecordFieldInLocalPatternMatchDecl() {
CompilerTestUtilities.checkDefnForExpectedError(
"foo6b = let {_|y} = {a = \"foo\", b = \"bar\"}; in y;",
MessageKind.Error.InvalidRecordFieldInLocalPatternMatchDecl.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo7c = let (a, b, c, d) = ('a', 'b', 'c'); in a;",
MessageKind.Error.InvalidRecordFieldInLocalPatternMatchDecl.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"foo7d = let {a, b} = {a = 'a'}; in a;",
MessageKind.Error.InvalidRecordFieldInLocalPatternMatchDecl.class, leccCALServices);
}
/**
* Tests that a non-polymorphic record pattern (or a tuple pattern) is able to constrain the type of the RHS.
*/
public void testNonPolymorphicRecordPatternConstrainingTypeOfRHS() {
CompilerTestUtilities.checkDefnForExpectedError(
"test = (\\t -> let (a,b) = t; in (a,b)) (1.0, 2.0, 3.0);",
MessageKind.Error.TypeErrorDuringApplication.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"test = (\\r -> let {a} = r; in a) {a='a', b='b'};",
MessageKind.Error.TypeErrorDuringApplication.class, leccCALServices);
}
/**
* Tests that a polymorphic record pattern is able to constrain the type of the RHS.
*/
public void testPolymorphicRecordPatternConstrainingTypeOfRHS() {
CompilerTestUtilities.checkDefnForExpectedError(
"test = (\\r -> let {_|#1,#2,a} = r; in a) ('x', 'y');",
MessageKind.Error.TypeErrorDuringApplication.class, leccCALServices);
CompilerTestUtilities.checkDefnForExpectedError(
"test = (\\r -> let {_|#1,a} = r; in a) {a='a'};",
MessageKind.Error.TypeErrorDuringApplication.class, leccCALServices);
}
/**
* Tests the error message for when a CALDoc comment is associated with a local pattern match declaration, which is not allowed.
*/
public void testLocalPatternMatchDeclCannotHaveCALDocComment() {
// data cons pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let /** foo */ Prelude.Cons _ x = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclCannotHaveCALDocComment.class, leccCALServices);
// colon pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let /** foo */ _:y = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclCannotHaveCALDocComment.class, leccCALServices);
// tuple pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let /** foo */ (_, _, z) = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclCannotHaveCALDocComment.class, leccCALServices);
// record pattern
CompilerTestUtilities.checkDefnForExpectedError(
"foo = let /** foo */ {_|a} = Prelude.undefined; in 3.0;",
MessageKind.Error.LocalPatternMatchDeclCannotHaveCALDocComment.class, leccCALServices);
}
}