/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 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/>. */ package org.catrobat.catroid.test.content.sprite; import android.test.AndroidTestCase; import android.util.Log; import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.content.Project; import org.catrobat.catroid.content.Scene; import org.catrobat.catroid.content.Script; import org.catrobat.catroid.content.SingleSprite; import org.catrobat.catroid.content.Sprite; import org.catrobat.catroid.content.StartScript; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.content.bricks.ChangeBrightnessByNBrick; import org.catrobat.catroid.content.bricks.ChangeXByNBrick; import org.catrobat.catroid.content.bricks.ShowTextBrick; import org.catrobat.catroid.content.bricks.UserBrick; import org.catrobat.catroid.content.bricks.UserScriptDefinitionBrick; import org.catrobat.catroid.content.bricks.UserScriptDefinitionBrickElement; import org.catrobat.catroid.formulaeditor.DataContainer; import org.catrobat.catroid.formulaeditor.Formula; import org.catrobat.catroid.formulaeditor.FormulaElement; import org.catrobat.catroid.formulaeditor.FormulaElement.ElementType; import org.catrobat.catroid.formulaeditor.InterpretationException; import org.catrobat.catroid.formulaeditor.UserVariable; import org.catrobat.catroid.test.utils.TestUtils; import java.util.HashSet; import java.util.List; import java.util.Set; public class SpriteTest extends AndroidTestCase { private static final String LOCAL_VARIABLE_NAME = "test_local"; private static final double LOCAL_VARIABLE_VALUE = 0xDEADBEEF; private static final String GLOBAL_VARIABLE_NAME = "test_global"; private static final double GLOBAL_VARIABLE_VALUE = 0xC0FFEE; private static final String TAG = SpriteTest.class.getName(); private Sprite sprite; private Project project; @Override protected void setUp() throws Exception { super.setUp(); sprite = new SingleSprite("testSprite"); project = new Project(getContext(), TestUtils.DEFAULT_TEST_PROJECT_NAME); project.getDefaultScene().addSprite(sprite); project.getDefaultScene().getDataContainer().addSpriteUserVariableToSprite(sprite, LOCAL_VARIABLE_NAME); project.getDefaultScene().getDataContainer().getUserVariable(LOCAL_VARIABLE_NAME, sprite).setValue(LOCAL_VARIABLE_VALUE); project.getDefaultScene().getDataContainer().addProjectUserVariable(GLOBAL_VARIABLE_NAME); project.getDefaultScene().getDataContainer().getUserVariable(GLOBAL_VARIABLE_NAME, null).setValue(GLOBAL_VARIABLE_VALUE); ProjectManager.getInstance().setProject(project); } public void testAddScript() { Sprite sprite = new SingleSprite("new SingleSprite"); Script firstScript = new StartScript(); Script secondScript = new StartScript(); sprite.addScript(firstScript); assertEquals("Script list does not contain script after adding", 1, sprite.getNumberOfScripts()); sprite.addScript(0, secondScript); assertEquals("Script list does not contain script after adding", 2, sprite.getNumberOfScripts()); assertEquals("Script list does not contain script after adding", 1, sprite.getScriptIndex(firstScript)); assertEquals("Script list does not contain script after adding", 0, sprite.getScriptIndex(secondScript)); sprite.removeAllScripts(); assertEquals("Script list could not be cleared", 0, sprite.getNumberOfScripts()); } public void testGetScript() { Sprite sprite = new SingleSprite("new SingleSprite"); Script firstScript = new StartScript(); Script secondScript = new StartScript(); sprite.addScript(firstScript); sprite.addScript(secondScript); assertEquals("Scripts do not match after retrieving", firstScript, sprite.getScript(0)); assertEquals("Script doo not match after retrieving", secondScript, sprite.getScript(1)); } public void testRemoveAllScripts() { Sprite sprite = new SingleSprite("new SingleSprite"); Script firstScript = new StartScript(); Script secondScript = new StartScript(); sprite.addScript(firstScript); sprite.addScript(secondScript); sprite.removeAllScripts(); assertEquals("Script list was not cleared", 0, sprite.getNumberOfScripts()); } public void testRemoveScript() { Sprite sprite = new SingleSprite("new SingleSprite"); Script firstScript = new StartScript(); Script secondScript = new StartScript(); sprite.addScript(firstScript); sprite.addScript(secondScript); sprite.removeScript(firstScript); assertEquals("Wrong script list size", 1, sprite.getNumberOfScripts()); assertEquals("Wrong script remained", secondScript, sprite.getScript(0)); } public void testGetScriptIndex() { Sprite sprite = new SingleSprite("new SingleSprite"); Script firstScript = new StartScript(); Script secondScript = new StartScript(); sprite.addScript(firstScript); sprite.addScript(secondScript); assertEquals("Indexes do not match", 0, sprite.getScriptIndex(firstScript)); assertEquals("Indexes do not match", 1, sprite.getScriptIndex(secondScript)); } public void testSpriteCloneWithLocalVariable() { Script script = new StartScript(); Brick brick = new ChangeBrightnessByNBrick(new Formula(new FormulaElement(ElementType.USER_VARIABLE, LOCAL_VARIABLE_NAME, null))); script.addBrick(brick); sprite.addScript(script); Sprite clonedSprite = sprite.clone(); UserVariable clonedVariable = project.getDefaultScene().getDataContainer().getUserVariable(LOCAL_VARIABLE_NAME, clonedSprite); assertNotNull("local variable isn't copied properly", clonedVariable); assertEquals("variable not cloned properly", LOCAL_VARIABLE_NAME, clonedVariable.getName()); assertEquals("variable not cloned properly", LOCAL_VARIABLE_VALUE, clonedVariable.getValue()); List<UserVariable> userVariableList = project.getDefaultScene().getDataContainer().getOrCreateVariableListForSprite(clonedSprite); Set<String> hashSet = new HashSet<>(); for (UserVariable userVariable : userVariableList) { assertTrue("Variable already exists", hashSet.add(userVariable.getName())); } } public void testSpriteCloneWithUserBrick() { Integer moveValue = 0; Integer secondMoveValue = 4; UserBrick outerUserBrick = new UserBrick(new UserScriptDefinitionBrick()); outerUserBrick.getDefinitionBrick().addUIText("outerBrick"); outerUserBrick.getDefinitionBrick().addUILocalizedVariable("outerBrickVariable"); sprite.addUserBrick(outerUserBrick); outerUserBrick.updateUserBrickParametersAndVariables(); Formula innerFormula = new Formula(new FormulaElement(ElementType.USER_VARIABLE, "outerBrickVariable", null)); outerUserBrick.getDefinitionBrick().getUserScript().addBrick(new ChangeXByNBrick(innerFormula)); StartScript startScript = new StartScript(); sprite.addScript(startScript); UserBrick outerBrickCopy = outerUserBrick.copyBrickForSprite(sprite); setOneFormula(outerBrickCopy, ElementType.NUMBER, moveValue.toString(), (float) moveValue, 1); startScript.addBrick(outerUserBrick); startScript.addBrick(outerBrickCopy); sprite.addUserBrick(outerBrickCopy); Sprite clonedSprite = sprite.clone(); checkUserBrickSpriteClones(sprite, clonedSprite, 0); checkUserBrickSpriteClones(sprite, clonedSprite, 1); UserBrick clonedInnerBrick = (UserBrick) clonedSprite.getScript(0).getBrickList().get(0); setOneFormula(clonedInnerBrick, ElementType.NUMBER, secondMoveValue.toString(), (float) secondMoveValue, 1); runScriptOnSprite(sprite, 0, moveValue); runScriptOnSprite(clonedSprite, 0, secondMoveValue); runScriptOnSprite(sprite, moveValue, moveValue); runScriptOnSprite(clonedSprite, secondMoveValue, secondMoveValue); runScriptOnSprite(sprite, moveValue * 2, moveValue); runScriptOnSprite(clonedSprite, secondMoveValue * 2, secondMoveValue); } private void checkUserBrickSpriteClones(Sprite originalSprite, Sprite clonedSprite, int indexOfUserbrick) { UserBrick brick = originalSprite.getUserBrickList().get(indexOfUserbrick); UserBrick clonedBrick = clonedSprite.getUserBrickList().get(indexOfUserbrick); assertNotSame("Cloned brick == original brick!", brick, clonedBrick); UserScriptDefinitionBrick originalDefinitionBrick = brick.getDefinitionBrick(); UserScriptDefinitionBrick clonedDefinitionBrick = clonedBrick.getDefinitionBrick(); assertNotSame("Cloned definition brick == original definition brick!", originalDefinitionBrick, clonedDefinitionBrick); assertNotSame("Cloned script == original script!", originalDefinitionBrick.getUserScript(), clonedDefinitionBrick.getUserScript()); assertNotSame("Cloned userBrickElements == original userBrickElements.", brick.getUserScriptDefinitionBrickElements(), clonedBrick.getUserScriptDefinitionBrickElements()); assertEquals("Cloned userBrickElements size != original userBrickElements size.", brick.getUserScriptDefinitionBrickElements().size(), clonedBrick.getUserScriptDefinitionBrickElements().size()); for (int elementPosition = 0; elementPosition < brick.getUserScriptDefinitionBrickElements().size(); elementPosition++) { UserScriptDefinitionBrickElement originalElement = brick.getUserScriptDefinitionBrickElements().get(elementPosition); UserScriptDefinitionBrickElement clonedElement = clonedBrick.getUserScriptDefinitionBrickElements().get(elementPosition); assertNotSame("Cloned userBrickElements element == original userBrickElements element." + ". arrayId: " + elementPosition, originalElement, clonedElement); boolean equivalent = checkArrayElementEquivalence(originalElement, clonedElement); assertTrue("Cloned userBrickElements element not equivalent to original userBrickElements element. " + ". arrayId: " + elementPosition, equivalent); } } public void testUserVariableVisibilityOfLocalVariablesInDifferentScenes() { String variableName = "sceneTestVariable"; Script script = new StartScript(); Brick firstBrick = new ChangeBrightnessByNBrick(0); script.addBrick(firstBrick); sprite.addScript(script); Scene secondScene = new Scene(getContext(), "scene 2", project); Sprite sprite2 = new SingleSprite("testSprite2"); Script secondScript = new StartScript(); Brick textBrick = new ShowTextBrick(10, 10); secondScript.addBrick(textBrick); sprite2.addScript(secondScript); secondScene.getDataContainer().addSpriteUserVariableToSprite(sprite2, variableName); UserVariable userVariable = secondScene.getDataContainer().getUserVariable(variableName, sprite2); userVariable.setValue(LOCAL_VARIABLE_VALUE); userVariable.setVisible(false); ProjectManager.getInstance().setSceneToPlay(secondScene); SequenceAction sequence = new SequenceAction(); sequence.addAction(sprite2.getActionFactory().createShowVariableAction(sprite2, new Formula(10), new Formula(10), userVariable)); secondScript.run(sprite2, sequence); DataContainer dataContainer = ProjectManager.getInstance().getSceneToPlay().getDataContainer(); userVariable = dataContainer.getUserVariable(variableName, sprite2); assertFalse("Variable should be invisible", userVariable.getVisible()); sequence.act(1f); userVariable = dataContainer.getUserVariable(variableName, sprite2); assertTrue("Variable should be visible", userVariable.getVisible()); } private void runScriptOnSprite(Sprite sprite, float expectedOriginalX, float expectedDeltaX) { assertEquals("Script has more than one script", 1, sprite.getNumberOfScripts()); Script startScript = sprite.getScript(0); SequenceAction sequence = new SequenceAction(); startScript.run(sprite, sequence); float x = sprite.look.getXInUserInterfaceDimensionUnit(); float y = sprite.look.getYInUserInterfaceDimensionUnit(); assertEquals("Unexpected initial sprite x position: ", expectedOriginalX, x); assertEquals("Unexpected initial sprite y position: ", 0f, y); sequence.act(1f); assertEquals("Unexpected final sprite x position: ", expectedOriginalX + expectedDeltaX, sprite.look.getXInUserInterfaceDimensionUnit()); assertEquals("Unexpected final sprite y position: ", 0f, sprite.look.getYInUserInterfaceDimensionUnit()); } private void setOneFormula(UserBrick subject, ElementType elementType, String value, Float expectedValue, int expectedFormulaListSize) { List<Formula> formulaList = subject.getFormulas(); assertEquals("formulaList.size() after innerBrick.updateUserBrickParameters()" + formulaList.size(), expectedFormulaListSize, formulaList.size()); for (Formula formula : formulaList) { formula.setRoot(new FormulaElement(elementType, value, null)); if (expectedValue != null) { try { assertEquals("Unexpected value from interpretFloat: ", expectedValue, formula.interpretFloat(sprite)); } catch (InterpretationException interpretationException) { Log.e(TAG, "InterpretationException!", interpretationException); } } } } private boolean checkArrayElementEquivalence(UserScriptDefinitionBrickElement leftHandSide, UserScriptDefinitionBrickElement rightHandSide) { boolean foundProblem; foundProblem = (leftHandSide.isLineBreak() != rightHandSide.isLineBreak()); foundProblem = foundProblem || (leftHandSide.isVariable() != rightHandSide.isVariable()); foundProblem = foundProblem || (leftHandSide.isNewLineHint() != rightHandSide.isNewLineHint()); foundProblem = foundProblem || (!leftHandSide.getText().equals(rightHandSide.getText())); return !foundProblem; } }