diff --git a/src/CattyTests/Formula/FormulaParserErrorDetectionTest.m b/src/CattyTests/Formula/FormulaParserErrorDetectionTest.m deleted file mode 100644 index 8c2cef8ff4..0000000000 --- a/src/CattyTests/Formula/FormulaParserErrorDetectionTest.m +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (C) 2010-2022 The Catrobat Team - * (http://developer.catrobat.org/credits) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * An additional term exception under section 7 of the GNU Affero - * General Public License, version 3, is available at - * (http://developer.catrobat.org/license_additional_term) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -#import -#import "Formula.h" -#import "FormulaElement.h" -#import "InternToken.h" -#import "InternFormulaParser.h" -#import "InternFormulaParserException.h" -#import "SpriteObject.h" -#import -#include -#import "Pocket_Code-Swift.h" - -@interface FormulaParserErrorDetectionTest : XCTestCase -@property(nonatomic, strong) FormulaManager* formulaManager; -@end - -@implementation FormulaParserErrorDetectionTest - -- (void)setUp { - [super setUp]; - self.formulaManager = [[FormulaManager alloc] initWithStageSize:[Util screenSize:true] andLandscapeMode: false]; -} - -- (void)testTooManyOperators -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.42"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: - - 42.42"); - XCTAssertEqual(1, internParser.errorTokenIndex, @"Error Token Index is not as expected"); - - [internTokenList removeAllObjects]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:PlusOperator.tag]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: +"); - XCTAssertEqual(0, internParser.errorTokenIndex, @"Error Token Index is not as expected"); - - [internTokenList removeAllObjects]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:PlusOperator.tag]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: + -"); - XCTAssertEqual(1, internParser.errorTokenIndex, @"Error Token Index is not as expected"); - - [internTokenList removeAllObjects]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MultOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: * 42.53"); - XCTAssertEqual(0, internParser.errorTokenIndex, @"Error Token Index is not as expected"); - - [internTokenList removeAllObjects]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.42"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.42"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: - 42.42 - 42.42 -"); - XCTAssertEqual(5, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -- (void) testOperatorMissing -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.52"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: 42.53 42.42"); - XCTAssertEqual(1, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -- (void) testNumberMissing -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MultOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: * 42.53"); - XCTAssertEqual(0, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -- (void) testRightBracketMissing -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: (42.53"); - XCTAssertEqual(2, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -- (void) testLeftBracketMissing -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Invalid formula parsed: 42.53)"); - XCTAssertEqual(1, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -- (void) testOutOfBound -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.53"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, "Invalid formula parsed: 42.53)"); - XCTAssertEqual(1, internParser.errorTokenIndex, @"Error Token Index is not as expected"); -} - -@end diff --git a/src/CattyTests/Formula/FormulaParserErrorDetectionTest.swift b/src/CattyTests/Formula/FormulaParserErrorDetectionTest.swift new file mode 100644 index 0000000000..2fec337220 --- /dev/null +++ b/src/CattyTests/Formula/FormulaParserErrorDetectionTest.swift @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2010-2023 The Catrobat Team + * (http://developer.catrobat.org/credits) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * (http://developer.catrobat.org/license_additional_term) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +import XCTest + +@testable import Pocket_Code + +class FormulaParserErrorDetectionTest: XCTestCase { + + var formulaTestHelper: FormulaTestHelper! + + override func setUp() { + super.setUp() + formulaTestHelper = FormulaTestHelper() + } + + func testTooManyOperators() { + var internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: - - 42.42", andExpectedErrorCode: 1) + + internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: +", andExpectedErrorCode: 0) + + internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: + -", andExpectedErrorCode: 1) + + internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: * 42.53", andExpectedErrorCode: 0) + + internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: - 42.42 - 42.42 -", andExpectedErrorCode: 5) + } + + func testOperatorMissing() { + let internTokenList = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: 42.53 42.42", andExpectedErrorCode: 1) + } + + func testNumberMissing() { + let internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: * 42.53", andExpectedErrorCode: 0) + } + + func testRightBracketMissing() { + let internTokenList = [InternToken(type: TOKEN_TYPE_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: (42.53", andExpectedErrorCode: 2) + } + + func testLeftBracketMissing() { + let internTokenList = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!, + InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: 42.53)", andExpectedErrorCode: 1) + } + + func testOutOfBound() { + let internTokenList = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.53")!, + InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Invalid formula parsed: 42.53)", andExpectedErrorCode: 1) + } +} diff --git a/src/CattyTests/Formula/FormulaParserFunctionsTest.m b/src/CattyTests/Formula/FormulaParserFunctionsTest.m deleted file mode 100644 index d87a98e5f6..0000000000 --- a/src/CattyTests/Formula/FormulaParserFunctionsTest.m +++ /dev/null @@ -1,362 +0,0 @@ -/** - * Copyright (C) 2010-2022 The Catrobat Team - * (http://developer.catrobat.org/credits) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * An additional term exception under section 7 of the GNU Affero - * General Public License, version 3, is available at - * (http://developer.catrobat.org/license_additional_term) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -#import -#import "Formula.h" -#import "FormulaElement.h" -#import "InternToken.h" -#import "InternFormulaParser.h" -#import "InternFormulaParserException.h" -#import "SpriteObject.h" -#import "Util.h" -#import -#include -#import "Pocket_Code-Swift.h" - -@interface FormulaParserFunctionsTest : XCTestCase -@property (nonatomic, strong) FormulaManager* formulaManager; -@property (nonatomic, strong) id interpreter; -@property (nonatomic, strong) SpriteObject *spriteObject; -@end - -@implementation FormulaParserFunctionsTest - -#define EPSILON 0.01 - -- (void)setUp -{ - self.formulaManager = [[FormulaManager alloc] initWithStageSize:[Util screenSize:true] andLandscapeMode: false]; - self.interpreter = (id)self.formulaManager; - self.spriteObject = [[SpriteObject alloc] init]; -} - -- (void) testSin -{ - Formula *formula = [self getFormula:@"SIN" value:@"90"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: sin(90)"); - XCTAssertEqual(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testCos -{ - Formula *formula = [self getFormula:@"COS" value:@"180"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: cos(180)"); - XCTAssertEqual(-1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testTan -{ - Formula *formula = [self getFormula:@"TAN" value:@"180"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: tan(180)"); - XCTAssertEqualWithAccuracy(0, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); -} - -- (void) testLn -{ - Formula *formula = [self getFormula:@"LN" value:@"2.7182818"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: ln(e)"); - XCTAssertEqualWithAccuracy(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); -} - -- (void) testLog -{ - Formula *formula = [self getFormula:@"LOG" value:@"10"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: log(10)"); - XCTAssertEqual(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testPi -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"PI"]]; // TODO use Function property - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: pi"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(M_PI, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testSqrt -{ - Formula *formula = [self getFormula:@"SQRT" value:@"100"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: sqrt(100)"); - XCTAssertEqual(10, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testExp -{ - Formula *formula = [self getFormula:@"EXP" value:@"3"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: exp(0)"); - XCTAssertEqualWithAccuracy(20.08f, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], 0.1f, @"Formula interpretation is not as expected"); -} - -- (void) testRandomNaturalNumbers -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"RAND"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"0"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"1"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: random(0,1)"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - double result = [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject]; - XCTAssertTrue(result == 0 || result == 1, @"Formula interpretation is not as expected"); -} - -- (void) testRound -{ - Formula *formula = [self getFormula:@"ROUND" value:@"1.33333"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: round(1.33333)"); - XCTAssertEqual(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testMod -{ - for (int offset = 0; offset < 10; offset += 1) { - int dividend = 1 + offset; - int divisor = 1 + offset; - - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MOD"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", dividend]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", divisor]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, "Formula is not parsed correctly: mod(%i, %i)", dividend, divisor); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqualWithAccuracy(0, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); - } - - for (int offset = 0; offset < 100; offset += 2) { - int dividend = 3 + offset; - int divisor = 2 + offset; - - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MOD"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", dividend]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", divisor]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, "Formula is not parsed correctly: mod(%i, %i)", dividend, divisor); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqualWithAccuracy(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); - } - - for (int offset = 0; offset < 10; offset += 1) { - int dividend = 3 + offset; - int divisor = 5 + offset; - - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MOD"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", dividend]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", divisor]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, "Formula is not parsed correctly: mod(%i, %i)", dividend, divisor); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqualWithAccuracy(dividend, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, "Formula interpretation is not as expected"); - } - - for (int offset = 0; offset < 10; offset += 1) { - int dividend = -3 - offset; - int divisor = 2 + offset; - - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MOD"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", abs(dividend)]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:[NSString stringWithFormat:@"%i", divisor]]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: mod(%i, %i)", dividend, divisor); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqualWithAccuracy(1 + offset, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); - } -} - -- (void) testAbs -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"ABS"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"1"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: abs(-1)"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(1, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testInvalidFunction -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"INVALID_FUNCTION"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"1"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNil(parseTree, @"Formula parsed but should not: INVALID_FUNCTION(1)"); - XCTAssertEqual(0, internParser.errorTokenIndex, @"Formula error value is not as expected"); -} - -- (void) testTrue -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"TRUE"]]; // TODO use Function property - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: true"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(1.0, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testFalse -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"FALSE"]]; // TODO use Function property - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: false"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(0.0, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testArcsin -{ - Formula *formula = [self getFormula:@"ARCSIN" value:@"1"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: arcsin(1)"); - XCTAssertEqualWithAccuracy(90, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); -} - -- (void) testArccos -{ - Formula *formula = [self getFormula:@"ARCCOS" value:@"0"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: arccos(0)"); - XCTAssertEqualWithAccuracy(90, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); -} - -- (void) testArctan -{ - Formula *formula = [self getFormula:@"ARCTAN" value:@"1"]; // TODO use Function property - XCTAssertNotNil(formula, @"Formula is not parsed correctly: arctan(1)"); - XCTAssertEqualWithAccuracy(45, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], EPSILON, @"Formula interpretation is not as expected"); -} - -- (void) testMax -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MAX"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"3"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"4"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: max(3,4)"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(4, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (void) testMin -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:@"MIN"]]; // TODO use Function property - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"3"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"4"]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: min(3,4)"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(3, [self.interpreter interpretDouble:formula forSpriteObject:self.spriteObject], @"Formula interpretation is not as expected"); -} - -- (Formula*)getFormula:(NSString*)tag value:(NSString*)value -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc] init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_NAME AndValue:tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:value]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - return [[Formula alloc] initWithFormulaElement:[internParser parseFormulaForSpriteObject:nil]]; -} - -@end diff --git a/src/CattyTests/Formula/FormulaParserFunctionsTest.swift b/src/CattyTests/Formula/FormulaParserFunctionsTest.swift new file mode 100644 index 0000000000..1dff781271 --- /dev/null +++ b/src/CattyTests/Formula/FormulaParserFunctionsTest.swift @@ -0,0 +1,219 @@ +/** + * Copyright (C) 2010-2023 The Catrobat Team + * (http://developer.catrobat.org/credits) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * (http://developer.catrobat.org/license_additional_term) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +import XCTest + +@testable import Pocket_Code + +class FormulaParserFunctionsTest: XCTestCase { + + var formulaTestHelper: FormulaTestHelper! + let EPSILON = 0.01 + + override func setUp() { + super.setUp() + formulaTestHelper = FormulaTestHelper() + } + + func testSin() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "SIN", andValue: "90") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "sin(90)", andExpectedResult: 1) + } + + func testCos() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "COS", andValue: "180") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "cos(90)", andExpectedResult: -1) + } + + func testTan() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "TAN", andValue: "180") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "tan(90)", andExpectedResult: 0.0, withAccuracy: EPSILON) + } + + func testLn() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "LN", andValue: "2.7182818") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "ln(2.7182818)", andExpectedResult: 1.0, withAccuracy: EPSILON) + } + + func testLog() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "LOG", andValue: "10") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "log(10)", andExpectedResult: 1) + } + + func testPi() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "PI")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "PI", andExpectedResult: Double.pi) + } + + func testSqrt() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "SQRT", andValue: "100") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "sqrt(100)", andExpectedResult: 10) + } + + func testExp() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "EXP", andValue: "3") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "exp(3)", andExpectedResult: 20.08, withAccuracy: 0.1) + } + + func testRandomNaturalNumbers() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "RAND")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + let parser = InternFormulaParser(tokens: internTokenList, andFormulaManager: formulaTestHelper.formulaManager) + let parseTree = parser?.parseFormula(for: nil) + XCTAssertNotNil(parseTree, "Formula is not parsed correctly!") + + let formula = Formula(formulaElement: parseTree)! + let result = formulaTestHelper.interpreter.interpretDouble(formula, for: formulaTestHelper.spriteObject) + XCTAssertTrue(result == 1 || result == 0, "Formula interpretation is not as expected!") + } + + func testRound() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "ROUND", andValue: "1.33333") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "round(1.33333)", andExpectedResult: 1.0) + } + + func testMod() { + for offset in 0...9 { + let dividend = 1 + offset + let divisor = 1 + offset + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MOD")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(dividend))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(divisor))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "mod(\(dividend), \(divisor))", andExpectedResult: 0.0, withAccuracy: EPSILON) + } + + for offset in stride(from: 0, to: 100, by: 2) { + let dividend = 3 + offset + let divisor = 2 + offset + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MOD")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(dividend))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(divisor))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "mod(\(dividend), \(divisor))", andExpectedResult: 1.0, withAccuracy: EPSILON) + } + + for offset in 0...9 { + let dividend = 3 + offset + let divisor = 5 + offset + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MOD")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(dividend))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(divisor))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "mod(\(dividend), \(divisor))", andExpectedResult: Double(dividend), withAccuracy: EPSILON) + } + + for offset in 0...9 { + let dividend = -3 - offset + let divisor = 2 + offset + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MOD")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(abs(dividend)))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: String(divisor))!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "mod(-\(abs(dividend)), \(divisor))", andExpectedResult: Double(1 + offset), withAccuracy: EPSILON) + } + } + + func testAbs() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "ABS")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "abs(1)", andExpectedResult: 1) + } + + func testInvalidFunction() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "INVALID_FUNCTION")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "Formula parsed but should not: INVALID_FUNCTION(1)", andExpectedErrorCode: 0) + } + + func testTrue() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "TRUE")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "TRUE", andExpectedResult: 1.0) + } + + func testFalse() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "FALSE")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "FALSE", andExpectedResult: 0.0) + } + + func testArcsin() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "ARCSIN", andValue: "1") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "arcsin(1)", andExpectedResult: 90.0) + } + + func testArccos() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "ARCCOS", andValue: "0") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "arccos(0)", andExpectedResult: 90.0) + } + + func testArctan() { + let internTokenList = addOpeningAndClosingBrackets(withTag: "ARCTAN", andValue: "1") + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "arctan(1)", andExpectedResult: 45.0) + } + + func testMax() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MAX")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "4")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "max(3,4)", andExpectedResult: 4.0) + } + + func testMin() { + let internTokenList = [InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: "MIN")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETER_DELIMITER)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "4")!, + InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "min(3,4)", andExpectedResult: 3.0) + } + + func addOpeningAndClosingBrackets(withTag tag: String, andValue value: String) -> [InternToken] { + var internTokenList = [InternToken]() + internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: tag)) + internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_OPEN)) + internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: value)) + internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) + return internTokenList + } +} diff --git a/src/CattyTests/Formula/FormulaParserOperatorsTest.m b/src/CattyTests/Formula/FormulaParserOperatorsTest.m deleted file mode 100644 index d6887be743..0000000000 --- a/src/CattyTests/Formula/FormulaParserOperatorsTest.m +++ /dev/null @@ -1,500 +0,0 @@ -/** - * Copyright (C) 2010-2022 The Catrobat Team - * (http://developer.catrobat.org/credits) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * An additional term exception under section 7 of the GNU Affero - * General Public License, version 3, is available at - * (http://developer.catrobat.org/license_additional_term) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -#import -#import -#import "InternFormulaUtils.h" -#import "InternFormula.h" -#import "Pocket_Code-Swift.h" - -@interface FormulaParserOperatorsTest : XCTestCase -@property (nonatomic, strong) FormulaManager* formulaManager; -@property (nonatomic, strong) id interpreter; -@end - -@implementation FormulaParserOperatorsTest - -- (void)setUp { - [super setUp]; - self.formulaManager = [[FormulaManager alloc] initWithStageSize:[Util screenSize:true] andLandscapeMode: false]; - self.interpreter = (id)self.formulaManager; -} - -- (NSMutableArray *)buildBinaryOperator:(InternTokenType)firstTokenType - firstValue:(NSString *)firstValue - withOperator:(NSString*)operatorTag - secondTokenType:(InternTokenType)secondTokenType - secondValue:(NSString *)secondValue -{ - NSMutableArray *internTokens = [[NSMutableArray alloc] init]; - [internTokens addObject:[[InternToken alloc] initWithType:firstTokenType AndValue:firstValue]]; - [internTokens addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:operatorTag]]; - [internTokens addObject:[[InternToken alloc] initWithType:secondTokenType AndValue:secondValue]]; - - return internTokens; -} - -- (NSMutableArray *)mergeOperatorLists:(NSMutableArray *)firstList - withOperator:(NSString*)operatorTag - andSecondList:(NSMutableArray *)secondList -{ - [firstList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:operatorTag]]; - [firstList addObjectsFromArray:secondList]; - - return firstList; -} - -- (NSMutableArray *)appendOperationToList:(NSMutableArray *)internTokenList - withOperator:(NSString*)operatorTag - andTokenType:(InternTokenType)tokenType - withValue:(NSString *)value -{ - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:operatorTag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:tokenType AndValue:value]]; - - return internTokenList; -} - -- (void)binaryOperatorTest:(NSMutableArray *)internTokens withExpectedResult:(NSString *)result -{ - InternFormulaParser *parser = [[InternFormulaParser alloc] initWithTokens:internTokens andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [parser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly!"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual([self.interpreter interpretInteger:formula forSpriteObject:[[SpriteObject alloc] init]], [result intValue], @"Formula interpretation is not as expected!"); -} - -- (void)testOperatorChain -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - firstTerm = [self appendOperationToList:firstTerm withOperator:MultOperator.tag andTokenType:TOKEN_TYPE_NUMBER withValue:@"3"]; - NSMutableArray *secontTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"2" withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - firstTerm = [self mergeOperatorLists:firstTerm withOperator:MultOperator.tag andSecondList:secontTerm]; - - [self binaryOperatorTest:firstTerm withExpectedResult:@"14"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - secontTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"3" withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - firstTerm = [self mergeOperatorLists:firstTerm withOperator:MultOperator.tag andSecondList:secontTerm]; - - [self binaryOperatorTest:firstTerm withExpectedResult:@"13"]; - -} - -- (void)testOperatorLeftBinding -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"5" withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"4"]; - [self appendOperationToList:firstTerm withOperator:MinusOperator.tag andTokenType:TOKEN_TYPE_NUMBER withValue:@"1"]; - - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"100" withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"10"]; - [self appendOperationToList:firstTerm withOperator:DivideOperator.tag andTokenType:TOKEN_TYPE_NUMBER withValue:@"10"]; - - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; -} - -- (void)testOperatorPriority -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - [self appendOperationToList:firstTerm withOperator:MultOperator.tag andTokenType:TOKEN_TYPE_NUMBER withValue:@"2"]; - - [self binaryOperatorTest:firstTerm withExpectedResult:@"-3"]; -} - -- (void)testUnaryMinus -{ - - NSMutableArray *internTokenList = [[NSMutableArray alloc]init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:MinusOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"42.42"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly: - 42.42"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual([self.interpreter interpretDouble:formula forSpriteObject:[[SpriteObject alloc] init]], -42.42, @"Formula interpretation is not as expected"); -} - -- (void)testGreaterThan -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"2" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"2" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:GreaterThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"2"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - -} - -- (void)testGreaterOrEqualThan -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"2" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"2" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:GreaterOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"2"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - -} - -- (void)testSmallerThan -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"2" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"2" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:SmallerThanOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"2"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; -} - -- (void)testSmallerOrEqualThan -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"2" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"2"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"2" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:SmallerOrEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"2"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; -} - -- (void)testEqual -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"5"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1.0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1.0" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1.0" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1.9"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"equalString" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"equalString"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1.0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1.0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"!`\"§$%&/()=?" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"!`\"§$%&/()=????"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"555.555" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"055.77.77"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; -} - -- (void)testNotEqual -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"5"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1.0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1.0" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1.0" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1.9"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"equalString" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"equalString"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1.0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"!`\"§$%&/()=?" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"!`\"§$%&/()=????"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"555.555" withOperator:NotEqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"055.77.77"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1,555.555" withOperator:EqualOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1555.555"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; -} - -- (void)testNot -{ - NSMutableArray *internTokenList = [[NSMutableArray alloc]init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:NotOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"1"]]; - - InternFormulaParser *internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - FormulaElement *parseTree = [internParser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly!"); - - Formula *formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(0.0, [self.interpreter interpretDouble:formula forSpriteObject:[[SpriteObject alloc] init]]); - - internTokenList = [[NSMutableArray alloc]init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:NotOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_NUMBER AndValue:@"0"]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly!"); - - formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual([self.interpreter interpretDouble:formula forSpriteObject:[[SpriteObject alloc] init]], 1.0); - - internTokenList = [[NSMutableArray alloc]init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:NotOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_STRING AndValue:@"1"]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly!"); - - formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(0.0, [self.interpreter interpretDouble:formula forSpriteObject:[[SpriteObject alloc] init]]); - - internTokenList = [[NSMutableArray alloc]init]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_OPERATOR AndValue:NotOperator.tag]]; - [internTokenList addObject:[[InternToken alloc] initWithType:TOKEN_TYPE_STRING AndValue:@"0"]]; - - internParser = [[InternFormulaParser alloc] initWithTokens:internTokenList andFormulaManager:self.formulaManager]; - parseTree = [internParser parseFormulaForSpriteObject:nil]; - XCTAssertNotNil(parseTree, @"Formula is not parsed correctly!"); - - formula = [[Formula alloc] initWithFormulaElement:parseTree]; - XCTAssertEqual(1.0, [self.interpreter interpretDouble:formula forSpriteObject:[[SpriteObject alloc] init]]); -} - -- (void)testAnd -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"0" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"0" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"0" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"0" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:AndOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; -} - -- (void)testOr -{ - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"0" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"0"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"1" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"1"]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"1"]; - - - NSMutableArray *secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"0" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"0" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"1"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; - - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:@"0" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"0"]; - - secondTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:@"1" withOperator:OrOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:@"0"]; - [self binaryOperatorTest:secondTerm withExpectedResult:@"1"]; -} - -- (void)testPlus -{ - NSString *firstOperand = @"1.3"; - NSString *secondOperand = @"3"; - NSString *result = @"4.3"; - - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstOperand = @"NotANumber"; - secondOperand = @"3.14"; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:PlusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"NaN"]; -} - -- (void)testDivision -{ - NSString *firstOperand = @"9.0"; - NSString *secondOperand = @"2"; - NSString *result = @"4.5"; - - - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstOperand = @"NotANumber"; - secondOperand = @"3.14"; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:DivideOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:nil]; -} - - -- (void)testMultiplication -{ - NSString *firstOperand = @"9.0"; - NSString *secondOperand = @"2"; - NSString *result = @"18.0"; - - - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstOperand = @"NotANumber"; - secondOperand = @"3.14"; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MultOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:nil]; -} - -- (void)testMinus -{ - NSString *firstOperand = @"9.0"; - NSString *secondOperand = @"2"; - NSString *result = @"7.0"; - - NSMutableArray *firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_NUMBER firstValue:firstOperand withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_STRING secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:result]; - - firstOperand = @"NotANumber"; - secondOperand = @"3.14"; - - firstTerm = [self buildBinaryOperator:TOKEN_TYPE_STRING firstValue:firstOperand withOperator:MinusOperator.tag secondTokenType:TOKEN_TYPE_NUMBER secondValue:secondOperand]; - [self binaryOperatorTest:firstTerm withExpectedResult:@"NaN"]; -} - -@end diff --git a/src/CattyTests/Formula/FormulaParserOperatorsTest.swift b/src/CattyTests/Formula/FormulaParserOperatorsTest.swift new file mode 100644 index 0000000000..3b14eede31 --- /dev/null +++ b/src/CattyTests/Formula/FormulaParserOperatorsTest.swift @@ -0,0 +1,459 @@ +/** + * Copyright (C) 2010-2023 The Catrobat Team + * (http://developer.catrobat.org/credits) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * (http://developer.catrobat.org/license_additional_term) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +import XCTest + +@testable import Pocket_Code + +final class FormulaParserOperatorsTest: XCTestCase { + + var formulaTestHelper: FormulaTestHelper! + + override func setUp() { + super.setUp() + formulaTestHelper = FormulaTestHelper() + } + + func testOperatorChain() { + var firstTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + var secondTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!] + + firstTerm = FormulaTestHelper.appendOperationToList(internTokenList: firstTerm, withOperator: MultOperator.tag, andTokenType: TOKEN_TYPE_NUMBER, withValue: "3") + firstTerm = FormulaTestHelper.mergeOperatorLists(firstList: firstTerm, withOperator: MultOperator.tag, andSecondList: secondTerm) + formulaTestHelper.interpretValidFormula(with: firstTerm, description: "1 + 2 * 3 * 2 + 1", andExpectedResult: 14) + + firstTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + secondTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + firstTerm = FormulaTestHelper.mergeOperatorLists(firstList: firstTerm, withOperator: MultOperator.tag, andSecondList: secondTerm) + formulaTestHelper.interpretValidFormula(with: firstTerm, description: "1 + 2 * 3 * 2", andExpectedResult: 13) + } + + func testOperatorLeftBinding() { + var firstTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "5")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "4")!] + firstTerm = FormulaTestHelper.appendOperationToList(internTokenList: firstTerm, withOperator: MinusOperator.tag, andTokenType: TOKEN_TYPE_NUMBER, withValue: "1") + formulaTestHelper.interpretValidFormula(with: firstTerm, description: "5 - 4 - 1", andExpectedResult: 0) + + firstTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "100")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: DivideOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "10")!] + firstTerm = FormulaTestHelper.appendOperationToList(internTokenList: firstTerm, withOperator: DivideOperator.tag, andTokenType: TOKEN_TYPE_NUMBER, withValue: "10") + formulaTestHelper.interpretValidFormula(with: firstTerm, description: "100 % 10 % 10", andExpectedResult: 1) + } + + func testOperatorPriority() { + var firstTerm = [InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")!, + InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + firstTerm = FormulaTestHelper.appendOperationToList(internTokenList: firstTerm, withOperator: MultOperator.tag, andTokenType: TOKEN_TYPE_NUMBER, withValue: "2") + formulaTestHelper.interpretValidFormula(with: firstTerm, description: "1 - 2 - 2", andExpectedResult: -3) + } + + func testUnaryMinus() { + let internTokenList = [InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "-42.42", andExpectedResult: -42.42) + } + + func testGreaterThan() { + let tokenGreaterThan = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterThanOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber2!, tokenGreaterThan!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 > 1", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenGreaterThan!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 1", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenGreaterThan!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 2", andExpectedResult: false) + + internTokenList = [tokenString2!, tokenGreaterThan!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 > 1", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenGreaterThan!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 1", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenGreaterThan!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 2", andExpectedResult: false) + } + + func testGreaterOrEqualThan() { + let tokenGreaterOrEqual = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterOrEqualOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber2!, tokenGreaterOrEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 2", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenGreaterOrEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 1", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenGreaterOrEqual!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 2", andExpectedResult: false) + + internTokenList = [tokenString2!, tokenGreaterOrEqual!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 >= 1", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenGreaterOrEqual!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 1", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenGreaterOrEqual!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 2", andExpectedResult: false) + } + + func testSmallerThan() { + let tokenSmallerThan = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerThanOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber2!, tokenSmallerThan!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 < 1", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenSmallerThan!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 < 1", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenSmallerThan!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 2", andExpectedResult: true) + + internTokenList = [tokenString2!, tokenSmallerThan!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 > 1", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenSmallerThan!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 1", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenSmallerThan!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 2", andExpectedResult: true) + } + + func testSmallerOrEqualThan() { + let tokenSmallerOrEqual = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerOrEqualOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber2!, tokenSmallerOrEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 <= 1", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenSmallerOrEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 <= 1", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenSmallerOrEqual!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 <= 2", andExpectedResult: true) + + internTokenList = [tokenString2!, tokenSmallerOrEqual!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 <= 1", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenSmallerOrEqual!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 <= 1", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenSmallerOrEqual!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 <= 2", andExpectedResult: true) + } + + func testEqual() { + let tokenEqual = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: EqualOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString10 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1.0") + + var internTokenList = [tokenNumber1!, tokenEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 1", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenEqual!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 2", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenEqual!, tokenString10!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 1.0", andExpectedResult: true) + + internTokenList = [tokenString10!, tokenEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.0 == 1", andExpectedResult: true) + + internTokenList = [tokenString10!, tokenEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "1.9")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.0 == 1.9", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenEqual!, tokenString10!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 1.0", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenEqual!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1.0")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 1.0", andExpectedResult: true) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "equalString")!, tokenEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "equalString")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "equalString == equalString", andExpectedResult: true) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "!`\"§$%&/()=?")!, tokenEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "!`\"§$%&/()=????")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!`\"§$%&/()=? == !`\"§$%&/()=????", andExpectedResult: false) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "555.555")!, tokenEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "055.77.77")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "555.555 == 055.77.77", andExpectedResult: false) + } + + func testNotEqual() { + let tokenNotEqual = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotEqualOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString10 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1.0") + + var internTokenList = [tokenNumber1!, tokenNotEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 1", andExpectedResult: false) + + internTokenList = [tokenNumber1!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 2", andExpectedResult: true) + + internTokenList = [tokenNumber1!, tokenNotEqual!, tokenString10!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 1.0", andExpectedResult: false) + + internTokenList = [tokenString10!, tokenNotEqual!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.0 != 1", andExpectedResult: false) + + internTokenList = [tokenString10!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "1.9")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.0 != 1.9", andExpectedResult: true) + + internTokenList = [tokenString1!, tokenNotEqual!, tokenString10!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 1.0", andExpectedResult: false) + + internTokenList = [tokenString1!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1.0")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 1.0", andExpectedResult: false) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "equalString")!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "equalString")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "equalString != equalString", andExpectedResult: false) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "!`\"§$%&/()=?")!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "!`\"§$%&/()=????")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!`\"§$%&/()=? != !`\"§$%&/()=????", andExpectedResult: true) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "555.555")!, tokenNotEqual!, + InternToken(type: TOKEN_TYPE_STRING, andValue: "055.77.77")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "555.555 != 055.77.77", andExpectedResult: true) + } + + func testNot() { + let tokenNot = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotOperator.tag) + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenNumber0 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + let tokenString0 = InternToken(type: TOKEN_TYPE_STRING, andValue: "0") + + var internTokenList = [tokenNot!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!1", andExpectedResult: false) + + internTokenList = [tokenNot!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!0", andExpectedResult: true) + + internTokenList = [tokenNot!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!1", andExpectedResult: false) + + internTokenList = [tokenNot!, tokenString0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "!0", andExpectedResult: true) + } + + func testAnd() { + let tokenAnd = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: AndOperator.tag) + let tokenNumber0 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0") + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenString0 = InternToken(type: TOKEN_TYPE_STRING, andValue: "0") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + + var internTokenList = [tokenNumber0!, tokenAnd!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 && 0", andExpectedResult: 0) + + internTokenList = [tokenNumber1!, tokenAnd!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 && 0", andExpectedResult: 0) + + internTokenList = [tokenNumber1!, tokenAnd!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 && 1", andExpectedResult: 1) + + internTokenList = [tokenString0!, tokenAnd!, tokenString0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 && 0", andExpectedResult: 0) + + internTokenList = [tokenString0!, tokenAnd!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 && 1", andExpectedResult: 0) + + internTokenList = [tokenString1!, tokenAnd!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 && 1", andExpectedResult: 1) + + internTokenList = [tokenNumber0!, tokenAnd!, tokenString0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 && 0", andExpectedResult: 0) + + internTokenList = [tokenString1!, tokenAnd!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 && 0", andExpectedResult: 0) + } + + func testOr() { + let tokenOr = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: OrOperator.tag) + let tokenNumber0 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0") + let tokenNumber1 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1") + let tokenString0 = InternToken(type: TOKEN_TYPE_STRING, andValue: "0") + let tokenString1 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1") + + var internTokenList = [tokenNumber0!, tokenOr!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 || 0", andExpectedResult: 0) + + internTokenList = [tokenNumber1!, tokenOr!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 || 0", andExpectedResult: 1) + + internTokenList = [tokenNumber1!, tokenOr!, tokenNumber1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 || 1", andExpectedResult: 1) + + internTokenList = [tokenString0!, tokenOr!, tokenString0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 || 0", andExpectedResult: 0) + + internTokenList = [tokenString0!, tokenOr!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 || 1", andExpectedResult: 1) + + internTokenList = [tokenString1!, tokenOr!, tokenString1!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 || 1", andExpectedResult: 1) + + internTokenList = [tokenNumber0!, tokenOr!, tokenString0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "0 || 0", andExpectedResult: 0) + + internTokenList = [tokenString1!, tokenOr!, tokenNumber0!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 || 0", andExpectedResult: 1) + } + + func testPlus() { + let result = 4.3 + let tokenPlus = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag) + let tokenNumber13 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1.3") + let tokenNumber3 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3") + let tokenString13 = InternToken(type: TOKEN_TYPE_STRING, andValue: "1.3") + let tokenString3 = InternToken(type: TOKEN_TYPE_STRING, andValue: "3") + + var internTokenList = [tokenNumber13!, tokenPlus!, tokenNumber3!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.3 + 3", andExpectedResult: result) + + internTokenList = [tokenString13!, tokenPlus!, tokenString3!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.3 + 3", andExpectedResult: result) + + internTokenList = [tokenNumber13!, tokenPlus!, tokenString3!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.3 + 3", andExpectedResult: result) + + internTokenList = [tokenString13!, tokenPlus!, tokenNumber3!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.3 + 3", andExpectedResult: result) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "NotANumber")!, tokenPlus!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3.14")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NotANumber + 3.14", andExpectedResult: "nan") + } + + func testDivision() { + let result = 4.5 + let tokenDivide = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: DivideOperator.tag) + let tokenNumber9 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "9.0") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString9 = InternToken(type: TOKEN_TYPE_STRING, andValue: "9.0") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber9!, tokenDivide!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 / 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenDivide!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 / 2", andExpectedResult: result) + + internTokenList = [tokenNumber9!, tokenDivide!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 / 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenDivide!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 / 2", andExpectedResult: result) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "NotANumber")!, tokenDivide!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3.14")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NotANumber / 3.14", andExpectedResult: "nan") + } + + func testMultiplication() { + let result = 18 + let tokenMult = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag) + let tokenNumber9 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "9.0") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString9 = InternToken(type: TOKEN_TYPE_STRING, andValue: "9.0") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber9!, tokenMult!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 * 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenMult!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 * 2", andExpectedResult: result) + + internTokenList = [tokenNumber9!, tokenMult!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 * 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenMult!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 * 2", andExpectedResult: result) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "NotANumber")!, tokenMult!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3.14")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NotANumber / 3.14", andExpectedResult: "nan") + } + + func testMinus() { + let result = 7 + let tokenMinus = InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag) + let tokenNumber9 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "9.0") + let tokenNumber2 = InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2") + let tokenString9 = InternToken(type: TOKEN_TYPE_STRING, andValue: "9.0") + let tokenString2 = InternToken(type: TOKEN_TYPE_STRING, andValue: "2") + + var internTokenList = [tokenNumber9!, tokenMinus!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 - 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenMinus!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 - 2", andExpectedResult: result) + + internTokenList = [tokenNumber9!, tokenMinus!, tokenString2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 - 2", andExpectedResult: result) + + internTokenList = [tokenString9!, tokenMinus!, tokenNumber2!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "9 - 2", andExpectedResult: result) + + internTokenList = [InternToken(type: TOKEN_TYPE_STRING, andValue: "NotANumber")!, tokenMinus!, + InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3.14")!] + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NotANumber - 3.14", andExpectedResult: "nan") + } +} diff --git a/src/CattyTests/Formula/FormulaParserTest.swift b/src/CattyTests/Formula/FormulaParserTest.swift index 569b95c855..9b5817f373 100644 --- a/src/CattyTests/Formula/FormulaParserTest.swift +++ b/src/CattyTests/Formula/FormulaParserTest.swift @@ -26,69 +26,47 @@ import XCTest final class FormulaParserTest: XCTestCase { - var formulaManager: FormulaManager! - var interpreter: FormulaInterpreterProtocol! - var spriteObject: SpriteObject! + var formulaTestHelper: FormulaTestHelper! override func setUp() { super.setUp() - let screenSize = Util.screenSize(true) - formulaManager = FormulaManager(stageSize: screenSize, landscapeMode: false) - interpreter = formulaManager - spriteObject = SpriteObject() - } - - func interpretInvalidFormula(with internTokenList: [InternToken], description: String, andExpectedErrorCode errorCode: Int32) { - let internParser = InternFormulaParser(tokens: internTokenList, andFormulaManager: formulaManager) - let parseTree = internParser?.parseFormula(for: nil) - XCTAssertNil(parseTree, "Parsed invalid formula " + description) - - XCTAssertEqual(errorCode, internParser?.errorTokenIndex, "Invalid error code for formula " + description) - } - - func interpretValidFormula(with internTokenList: [InternToken], description: String, andExpectedResult result: Double) { - let internParser = InternFormulaParser(tokens: internTokenList, andFormulaManager: formulaManager) - let parseTree = internParser?.parseFormula(for: nil) - XCTAssertNotNil(parseTree, "Could not parse formula " + description) - - let formula = Formula(formulaElement: parseTree) - XCTAssertEqual(result, interpreter.interpretDouble(formula!, for: spriteObject), "Invalid result for formula " + description) + formulaTestHelper = FormulaTestHelper() } func testEmptyInput() { let internTokenList = [InternToken]() - interpretInvalidFormula(with: internTokenList, description: "", andExpectedErrorCode: FORMULA_PARSER_NO_INPUT.rawValue) + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "", andExpectedErrorCode: FORMULA_PARSER_NO_INPUT.rawValue) } func testInvalidInput() { var internTokenList = [InternToken]() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "")) - interpretInvalidFormula(with: internTokenList, description: "", andExpectedErrorCode: 0) + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: "", andExpectedErrorCode: 0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: ".")) - interpretInvalidFormula(with: internTokenList, description: ".", andExpectedErrorCode: 0) + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: ".", andExpectedErrorCode: 0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: ".1")) - interpretInvalidFormula(with: internTokenList, description: ".1", andExpectedErrorCode: 0) + formulaTestHelper.interpretInvalidFormula(with: internTokenList, description: ".1", andExpectedErrorCode: 0) } func testNumbers() { var internTokenList = [InternToken]() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1.0")) - interpretValidFormula(with: internTokenList, description: "1.0", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1.0", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1", andExpectedResult: 1.0) } func testUnaryMinus() { var internTokenList = [InternToken]() internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "42.42")) - interpretValidFormula(with: internTokenList, description: "-42.42", andExpectedResult: -42.42) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "-42.42", andExpectedResult: -42.42) } func testGreaterOperators() { @@ -96,25 +74,25 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterThanOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "2 > 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 > 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterThanOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 > 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 > 1", andExpectedResult: 0.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterOrEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 >= 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: GreaterOrEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) - interpretValidFormula(with: internTokenList, description: "1 >= 2", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 >= 2", andExpectedResult: 0.0) } func testSmallerOperators() { @@ -122,25 +100,25 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerThanOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) - interpretValidFormula(with: internTokenList, description: "1 < 2", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 < 2", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerThanOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 < 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 < 1", andExpectedResult: 0.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerOrEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 <= 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 <= 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: SmallerOrEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "2 <= 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 <= 1", andExpectedResult: 0.0) } func testEqualOperators() { @@ -148,25 +126,25 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: EqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 == 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 == 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: EqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "2 == 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 == 1", andExpectedResult: 0.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "2 != 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "2 != 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotEqualOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "1 != 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 != 1", andExpectedResult: 0.0) } func testLogicalOperators() { @@ -175,28 +153,28 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: AndOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "NOT 0 AND 1", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NOT 0 AND 1", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: OrOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) - interpretValidFormula(with: internTokenList, description: "NOT 1 OR 0", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NOT 1 OR 0", andExpectedResult: 0.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: OrOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) - interpretValidFormula(with: internTokenList, description: "NOT 0 OR 0", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NOT 0 OR 0", andExpectedResult: 1.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: NotOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: AndOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) - interpretValidFormula(with: internTokenList, description: "NOT 0 AND 0", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "NOT 0 AND 0", andExpectedResult: 0.0) } func testOperatorPriority() { @@ -206,7 +184,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) - interpretValidFormula(with: internTokenList, description: "1 - 2 * 2", andExpectedResult: -3.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 - 2 * 2", andExpectedResult: -3.0) } func testOperatorLeftBinding() { @@ -216,7 +194,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "4")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "5 - 4 - 1", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "5 - 4 - 1", andExpectedResult: 0.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "100")) @@ -224,7 +202,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "10")) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: DivideOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "10")) - interpretValidFormula(with: internTokenList, description: "100 / 10 / 10", andExpectedResult: 1.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "100 / 10 / 10", andExpectedResult: 1.0) } func testOperatorChain() { @@ -241,7 +219,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) - interpretValidFormula(with: internTokenList, description: "(1 + 2 * 3) ^ 2 + 1", andExpectedResult: 50.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "(1 + 2 * 3) ^ 2 + 1", andExpectedResult: 50.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "1")) @@ -254,7 +232,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MultOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "1 + 2 ^ (3 * 2)", andExpectedResult: 65.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "1 + 2 ^ (3 * 2)", andExpectedResult: 65.0) } func testBrackets() { @@ -270,7 +248,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: PlusOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "(1 + 2) * (1 + 2)", andExpectedResult: 9.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "(1 + 2) * (1 + 2)", andExpectedResult: 9.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)) @@ -291,7 +269,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: MinusOperator.tag)) internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "2")) internTokenList.append(InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "-(1 ^ 2) - -(-1 - -2)", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "-(1 ^ 2) - -(-1 - -2)", andExpectedResult: 0.0) } func testBracketCorrection() { @@ -306,7 +284,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "10")) internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) internTokenList.append(InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "abs(2 * (5 - 10))", andExpectedResult: 10.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "abs(2 * (5 - 10))", andExpectedResult: 10.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "3")) @@ -319,7 +297,7 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_NUMBER, andValue: "0")) internTokenList.append(InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)) internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "3 * (2 + cos(0))", andExpectedResult: 9.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "3 * (2 + cos(0))", andExpectedResult: 9.0) internTokenList.removeAll() internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_NAME, andValue: ModFunction.tag)) @@ -340,6 +318,6 @@ final class FormulaParserTest: XCTestCase { internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) internTokenList.append(InternToken(type: TOKEN_TYPE_FUNCTION_PARAMETERS_BRACKET_CLOSE)) internTokenList.append(InternToken(type: TOKEN_TYPE_BRACKET_CLOSE)) - interpretValidFormula(with: internTokenList, description: "mod(1, mod(1, mod(5, (3))))", andExpectedResult: 0.0) + formulaTestHelper.interpretValidFormula(with: internTokenList, description: "mod(1, mod(1, mod(5, (3))))", andExpectedResult: 0.0) } } diff --git a/src/CattyTests/Formula/FormulaTestHelper.swift b/src/CattyTests/Formula/FormulaTestHelper.swift new file mode 100644 index 0000000000..e0bc740130 --- /dev/null +++ b/src/CattyTests/Formula/FormulaTestHelper.swift @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2010-2023 The Catrobat Team + * (http://developer.catrobat.org/credits) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * (http://developer.catrobat.org/license_additional_term) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +import XCTest + +@testable import Pocket_Code + +class FormulaTestHelper { + + var formulaManager: FormulaManager! + var interpreter: FormulaInterpreterProtocol! + var spriteObject: SpriteObject! + + init() { + let screenSize = Util.screenSize(true) + formulaManager = FormulaManager(stageSize: screenSize, landscapeMode: false) + interpreter = formulaManager + spriteObject = SpriteObject() + } + + static func mergeOperatorLists(firstList: [InternToken], withOperator operatorTag: String, andSecondList secondList: [InternToken]) -> [InternToken] { + var result = firstList + result.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: operatorTag)) + result.append(contentsOf: secondList) + return result + } + + static func appendOperationToList(internTokenList: [InternToken], withOperator operatorTag: String, andTokenType tokenType: InternTokenType, withValue value: String) -> [InternToken] { + var result = internTokenList + result.append(InternToken(type: TOKEN_TYPE_OPERATOR, andValue: operatorTag)) + result.append(InternToken(type: tokenType, andValue: value)) + return result + } + + func interpretValidFormula(with internTokens: [InternToken], description: String, andExpectedResult result: T) { + interpretValidFormula(with: internTokens, description: description, andExpectedResult: result, withAccuracy: Optional.none) + } + + func interpretValidFormula(with internTokens: [InternToken], description: String, andExpectedResult result: T, withAccuracy accuracy: U?) { + let parser = InternFormulaParser(tokens: internTokens, andFormulaManager: formulaManager) + let parseTree = parser?.parseFormula(for: nil) + XCTAssertNotNil(parseTree, "Could not parse formula " + description) + let formula = Formula(formulaElement: parseTree)! + + if accuracy != nil { + assertFormulaWithAccuracy(formula: formula, withResult: result, withAccuracy: accuracy) + } else { + assertFormula(formula: formula, withResult: result) + } + } + + private func assertFormula(formula: Formula, withResult result: T) { + let errorMessage = "Formula interpretation is not as expected!" + + switch type(of: result) { + case is Int.Type: + XCTAssertEqual(interpreter.interpretInteger(formula, for: spriteObject), result as! Int, errorMessage) + case is Double.Type: + XCTAssertEqual(interpreter.interpretDouble(formula, for: spriteObject), result as! Double, errorMessage) + case is Float.Type: + XCTAssertEqual(interpreter.interpretFloat(formula, for: spriteObject), result as! Float, errorMessage) + case is String.Type: + XCTAssertEqual(interpreter.interpretString(formula, for: spriteObject), result as! String, errorMessage) + case is Bool.Type: + XCTAssertEqual(interpreter.interpretBool(formula, for: spriteObject), result as! Bool, errorMessage) + default: + XCTAssertEqual(interpreter.interpretString(formula, for: spriteObject), result as! String, errorMessage) + } + } + + private func assertFormulaWithAccuracy(formula: Formula, withResult result: T, withAccuracy accuracy: U) { + let errorMessage = "Formula interpretation is not as expected!" + + switch type(of: result) { + case is Int.Type: + XCTAssertEqual(interpreter.interpretInteger(formula, for: spriteObject), result as! Int, accuracy: accuracy as! Int, errorMessage) + case is Double.Type: + XCTAssertEqual(interpreter.interpretDouble(formula, for: spriteObject), result as! Double, accuracy: accuracy as! Double, errorMessage) + case is Float.Type: + XCTAssertEqual(interpreter.interpretFloat(formula, for: spriteObject), result as! Float, accuracy: accuracy as! Float, errorMessage) + default: + XCTAssertEqual(interpreter.interpretString(formula, for: spriteObject), result as! String, errorMessage) + } + } + + func interpretInvalidFormula(with internTokenList: [InternToken], description: String, andExpectedErrorCode errorCode: Int32) { + let internParser = InternFormulaParser(tokens: internTokenList, andFormulaManager: formulaManager) + let parseTree = internParser?.parseFormula(for: nil) + XCTAssertNil(parseTree, "Parsed invalid formula " + description) + XCTAssertEqual(errorCode, internParser?.errorTokenIndex, "Invalid error code for formula " + description) + } + +}