/* * 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.uitest.devices.mindstorms.nxt; import android.widget.ListView; import org.catrobat.catroid.R; import org.catrobat.catroid.bluetooth.ConnectBluetoothDeviceActivity; import org.catrobat.catroid.common.LookData; import org.catrobat.catroid.common.ScreenValues; import org.catrobat.catroid.common.bluetooth.BluetoothTestUtils; import org.catrobat.catroid.common.bluetooth.ConnectionDataLogger; import org.catrobat.catroid.content.Project; 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.WhenScript; import org.catrobat.catroid.content.bricks.LegoNxtMotorMoveBrick; import org.catrobat.catroid.content.bricks.LegoNxtMotorStopBrick; import org.catrobat.catroid.content.bricks.LegoNxtMotorTurnAngleBrick; import org.catrobat.catroid.content.bricks.LegoNxtPlayToneBrick; import org.catrobat.catroid.content.bricks.SetLookBrick; import org.catrobat.catroid.content.bricks.WaitBrick; import org.catrobat.catroid.devices.mindstorms.nxt.sensors.NXTSensor; import org.catrobat.catroid.io.StorageHandler; import org.catrobat.catroid.stage.StageActivity; import org.catrobat.catroid.ui.MainMenuActivity; import org.catrobat.catroid.ui.MyProjectsActivity; import org.catrobat.catroid.ui.ProjectActivity; import org.catrobat.catroid.ui.SettingsActivity; import org.catrobat.catroid.uitest.annotation.Device; import org.catrobat.catroid.uitest.util.BaseActivityInstrumentationTestCase; import org.catrobat.catroid.uitest.util.UiTestUtils; import java.io.File; import java.util.ArrayList; public class LegoNXTImplTest extends BaseActivityInstrumentationTestCase<MainMenuActivity> { private static final int IMAGE_FILE_ID = org.catrobat.catroid.test.R.raw.icon; private static final int MOTOR_ACTION = 0; private static final int MOTOR_STOP = 1; private static final int MOTOR_TURN = 2; private static final int PLAY_TONE = 3; private static final String LOCAL_BLUETOOTH_TEST_DUMMY_DEVICE_NAME = "dummy_device"; private final String projectName = UiTestUtils.PROJECTNAME1; private final String spriteName = "testSprite"; public LegoNXTImplTest() { super(MainMenuActivity.class); } @Override public void setUp() throws Exception { super.setUp(); UiTestUtils.prepareStageForTest(); disableSensors(); SettingsActivity.disableLegoNXTMindstormsSensorInfoDialog( this.getInstrumentation().getTargetContext().getApplicationContext()); } private void disableSensors() { SettingsActivity.setLegoMindstormsNXTSensorMapping(this.getInstrumentation().getTargetContext(), new NXTSensor.Sensor[] { NXTSensor.Sensor.NO_SENSOR, NXTSensor.Sensor.NO_SENSOR, NXTSensor.Sensor.NO_SENSOR, NXTSensor.Sensor.NO_SENSOR }); } @Device public void testNXTFunctionality() { ArrayList<int[]> commands = createTestproject(projectName); BluetoothTestUtils.enableBluetooth(); ConnectionDataLogger logger = ConnectionDataLogger.createLocalConnectionLogger(); solo.clickOnText(solo.getString(R.string.main_menu_programs)); solo.waitForActivity(MyProjectsActivity.class.getSimpleName()); solo.clickOnText(projectName); UiTestUtils.clickOnBottomBar(solo, R.id.button_play); solo.sleep(1000); solo.assertCurrentActivity("Not in BTConnectDeviceActivity", ConnectBluetoothDeviceActivity.class); // use this only, if ConnectionDataLogger is in local mode (localProxy) BluetoothTestUtils.addPairedDevice(LOCAL_BLUETOOTH_TEST_DUMMY_DEVICE_NAME, (ConnectBluetoothDeviceActivity) solo.getCurrentActivity(), getInstrumentation()); int pairedDevicesIndex = 0; for (int listViewIdx = 0; listViewIdx < solo.getCurrentViews(ListView.class).size(); listViewIdx++) { if (solo.getCurrentViews(ListView.class).get(listViewIdx).getId() == R.id.paired_devices) { pairedDevicesIndex = listViewIdx; } } ListView deviceList = solo.getCurrentViews(ListView.class).get(pairedDevicesIndex); String connectedDeviceName = null; for (int i = 0; i < deviceList.getCount(); i++) { String deviceName = (String) deviceList.getItemAtPosition(i); if (deviceName.startsWith(LOCAL_BLUETOOTH_TEST_DUMMY_DEVICE_NAME)) { connectedDeviceName = deviceName; break; } } solo.clickOnText(connectedDeviceName); solo.sleep(2000); solo.assertCurrentActivity("Not in stage - connection to bluetooth-device failed", StageActivity.class); solo.sleep(2000); solo.clickOnScreen(ScreenValues.SCREEN_WIDTH / 2, ScreenValues.SCREEN_HEIGHT / 2); ArrayList<byte[]> executedCommands = logger.getSentMessages(2, commands.size()); assertEquals("Commands seem to have not been executed! Connected to correct device??", commands.size(), executedCommands.size()); solo.goBack(); solo.goBack(); int i = 0; for (int[] item : commands) { switch (item[0]) { case MOTOR_ACTION: assertEquals("Wrong motor was used!", item[1], executedCommands.get(i)[2]); assertEquals("Wrong speed was used!", item[2], executedCommands.get(i)[3]); break; case MOTOR_STOP: assertEquals("Wrong motor was used!", item[1], executedCommands.get(i)[2]); assertEquals("Motor didn't actually stop!", 0, executedCommands.get(i)[3]); break; case MOTOR_TURN: assertEquals("Wrong motor was used!", item[1], executedCommands.get(i)[2]); int turnValue = (0x000000FF & executedCommands.get(i)[8]); //unsigned types would be too smart for java, sorry no chance mate! turnValue += ((0x000000FF & executedCommands.get(i)[9]) << 8); turnValue += ((0x000000FF & executedCommands.get(i)[10]) << 16); turnValue += ((0x000000FF & executedCommands.get(i)[11]) << 24); int turnSpeed = 30; //fixed value in Brick, however LegoBot needs negative speed instead of negative angles if (item[2] < 0) { item[2] += -2 * item[2]; turnSpeed -= 2 * turnSpeed; } assertEquals("Motor turned wrong angle", item[2], turnValue); assertEquals("Motor didn't turn with fixed value 30!", turnSpeed, executedCommands.get(i)[3]); break; case PLAY_TONE: int frequency = (0x000000FF & executedCommands.get(i)[2]); frequency += ((0x000000FF & executedCommands.get(i)[3]) << 8); assertEquals("wrong frequency used", item[1], frequency); int duration = (0x000000FF & executedCommands.get(i)[4]); duration += ((0x000000FF & executedCommands.get(i)[5]) << 8); assertEquals("wrong duration used", item[2], duration); } i++; } logger.disconnectAndDestroy(); } @Device public void testNXTConnectionDialogGoBack() { createTestproject(projectName); BluetoothTestUtils.enableBluetooth(); solo.clickOnText(solo.getString(R.string.main_menu_programs)); solo.waitForActivity(MyProjectsActivity.class.getSimpleName()); solo.clickOnText(projectName); solo.waitForActivity(ProjectActivity.class.getSimpleName()); UiTestUtils.clickOnBottomBar(solo, R.id.button_play); solo.sleep(1000); solo.assertCurrentActivity("Devicelist not shown!", ConnectBluetoothDeviceActivity.class); solo.goBack(); solo.sleep(1000); UiTestUtils.clickOnBottomBar(solo, R.id.button_play); solo.sleep(1000); solo.assertCurrentActivity("Devicelist not shown!", ConnectBluetoothDeviceActivity.class); } private ArrayList<int[]> createTestproject(String projectName) { ArrayList<int[]> commands = new ArrayList<int[]>(); Sprite firstSprite = new SingleSprite(spriteName); Script startScript = new StartScript(); Script whenScript = new WhenScript(); SetLookBrick setLookBrick = new SetLookBrick(); LegoNxtMotorMoveBrick legoMotorActionBrick = new LegoNxtMotorMoveBrick( LegoNxtMotorMoveBrick.Motor.MOTOR_B_C, 100); commands.add(new int[] { MOTOR_ACTION, 1, 100 }); commands.add(new int[] { MOTOR_ACTION, 2, 100 }); WaitBrick firstWaitBrick = new WaitBrick(500); LegoNxtMotorStopBrick legoMotorStopBrick = new LegoNxtMotorStopBrick( LegoNxtMotorStopBrick.Motor.MOTOR_B_C); commands.add(new int[] { MOTOR_STOP, 1 }); commands.add(new int[] { MOTOR_STOP, 2 }); WaitBrick secondWaitBrick = new WaitBrick(500); LegoNxtMotorTurnAngleBrick legoMotorTurnAngleBrick = new LegoNxtMotorTurnAngleBrick( LegoNxtMotorTurnAngleBrick.Motor.MOTOR_C, 515); commands.add(new int[] { MOTOR_TURN, 2, 515 }); WaitBrick thirdWaitBrick = new WaitBrick(500); LegoNxtPlayToneBrick legoPlayToneBrick = new LegoNxtPlayToneBrick(50, 1.5f); //Tone does not return a command commands.add(new int[] { PLAY_TONE, 5000, 1500 }); whenScript.addBrick(legoMotorActionBrick); whenScript.addBrick(firstWaitBrick); whenScript.addBrick(legoMotorStopBrick); whenScript.addBrick(secondWaitBrick); whenScript.addBrick(legoMotorTurnAngleBrick); whenScript.addBrick(thirdWaitBrick); whenScript.addBrick(legoPlayToneBrick); startScript.addBrick(setLookBrick); firstSprite.addScript(startScript); firstSprite.addScript(whenScript); ArrayList<Sprite> spriteList = new ArrayList<>(); spriteList.add(firstSprite); Project project = UiTestUtils.createProject(projectName, spriteList, getActivity()); String imageName = "image"; File image = UiTestUtils.saveFileToProject(projectName, project.getDefaultScene().getName(), imageName, IMAGE_FILE_ID, getInstrumentation() .getContext(), UiTestUtils.FileTypes.IMAGE); LookData lookData = new LookData(); lookData.setLookFilename(image.getName()); lookData.setLookName(imageName); setLookBrick.setLook(lookData); firstSprite.getLookDataList().add(lookData); StorageHandler.getInstance().saveProject(project); return commands; } }