/* * Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.scvngr.levelup.core.ui.view; import android.graphics.Bitmap; import android.graphics.Color; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.test.AndroidTestCase; import com.scvngr.levelup.core.annotation.SlowOperation; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * Mock implementation of {@link com.scvngr.levelup.core.ui.view.LevelUpQrCodeGenerator} for test purposes. */ public final class MockQrCodeGenerator implements LevelUpQrCodeGenerator { /** * The x & y coordinate of the test color pixel. */ public static final int TEST_COLOR_PIXEL = 3; public static final int TEST_IMAGE_SIZE = 7; public static final int TARGET_TOP = 2; public static final int TARGET_BOTTOM = 4; public static final int TARGET_LEFT = 2; public static final int TARGET_RIGHT = 4; public static final String TEST_CONTENT1 = "foo"; public static final String TEST_CONTENT2 = "bar"; public static final String TEST_CONTENT3 = "baz"; public static final int TEST_CONTENT1_COLOR = Color.RED; public static final int TEST_CONTENT2_COLOR = Color.GREEN; public static final int TEST_CONTENT3_COLOR = Color.BLUE; public final LevelUpQrCodeImage mTestImage1; public final LevelUpQrCodeImage mTestImage2; public final LevelUpQrCodeImage mTestImage3; public CountDownLatch mGenerateDelayLatch; private static final int GENERATE_LATCH_WAIT_SECONDS = 4; public MockQrCodeGenerator() { mTestImage1 = generateTestImage(TEST_CONTENT1_COLOR); mTestImage2 = generateTestImage(TEST_CONTENT2_COLOR); mTestImage3 = generateTestImage(TEST_CONTENT3_COLOR); } /** * @param image the image to check. * @param code the code to check. * @return true if the given bitmap is the one representing the given code. */ public static boolean isBitmapForCode(@Nullable final LevelUpQrCodeImage image, @Nullable final String code) { boolean isEqual = false; if (null != image) { final int color = image.getBitmap().getPixel(TEST_COLOR_PIXEL, TEST_COLOR_PIXEL); switch (color) { case TEST_CONTENT1_COLOR: isEqual = TEST_CONTENT1.equals(code); break; case TEST_CONTENT2_COLOR: isEqual = TEST_CONTENT2.equals(code); break; case TEST_CONTENT3_COLOR: isEqual = TEST_CONTENT3.equals(code); break; default: isEqual = false; } } return isEqual; } /** * Generate a {@link com.scvngr.levelup.core.ui.view.LevelUpQrCodeGenerator.LevelUpQrCodeImage} * for the specified color. * * @param color the color to generate the image from * @return the {@link com.scvngr.levelup.core.ui.view.LevelUpQrCodeGenerator.LevelUpQrCodeImage} * . */ @NonNull private LevelUpQrCodeImage generateTestImage(final int color) { final Bitmap bitmap = Bitmap.createBitmap(TEST_IMAGE_SIZE, TEST_IMAGE_SIZE, Bitmap.Config.RGB_565); bitmap.setDensity(Bitmap.DENSITY_NONE); bitmap.setPixel(TEST_COLOR_PIXEL, TEST_COLOR_PIXEL, color); // These are the target markers. bitmap.setPixel(TARGET_RIGHT, TARGET_TOP, Color.BLACK); bitmap.setPixel(TARGET_RIGHT, TARGET_BOTTOM, Color.BLACK); bitmap.setPixel(TARGET_LEFT, TARGET_BOTTOM, Color.BLACK); final Bitmap immutableBitmap = Bitmap.createBitmap(bitmap); if (bitmap != immutableBitmap) { bitmap.recycle(); } return new LevelUpQrCodeImage(immutableBitmap, 1, 2); } /** * The mock version of this returns pre-rendered immutable bitmaps. These can be checked against * expected results using {@link #isBitmapForCode}. * * @param qrCodeData the QR code data string * @return the test * {@link com.scvngr.levelup.core.ui.view.LevelUpQrCodeGenerator.LevelUpQrCodeImage}. * @see com.scvngr.levelup.core.ui.view.LevelUpQrCodeGenerator#generateLevelUpQrCode */ @Override @NonNull @SlowOperation public LevelUpQrCodeImage generateLevelUpQrCode(@NonNull final String qrCodeData) { LevelUpQrCodeImage result; if (TEST_CONTENT1.equals(qrCodeData)) { result = mTestImage1; } else if (TEST_CONTENT2.equals(qrCodeData)) { result = mTestImage2; } else if (TEST_CONTENT3.equals(qrCodeData)) { result = mTestImage3; } else { // This is an error condition that will probably never occur in real life. throw new AssertionError(); } if (null != mGenerateDelayLatch) { try { mGenerateDelayLatch.await(); if (!mGenerateDelayLatch.await(GENERATE_LATCH_WAIT_SECONDS, TimeUnit.SECONDS)) { AndroidTestCase.fail("latch timeout exceeded"); } } catch (final InterruptedException e) { AndroidTestCase.fail("latch was interrupted"); } // As the latch has expired, remove it. mGenerateDelayLatch = null; } return result; } /** * Adds a {@link java.util.concurrent.CountDownLatch} starting at 1 to the {@link #generateLevelUpQrCode} * method to allow testing classes to forcibly delay the background task. Make sure to call this * method before calling {@link #generateLevelUpQrCode} or anything that may call it. * * @return the latch */ public CountDownLatch addCountdownLatch() { mGenerateDelayLatch = new CountDownLatch(1); return mGenerateDelayLatch; } }