content: package org.altbeacon.beacon;
  
  import android.content.Context;
  
  import org.altbeacon.beacon.logging.LogManager;
  import org.altbeacon.beacon.logging.Loggers;
  import org.altbeacon.beacon.utils.UrlBeaconUrlCompressor;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.robolectric.RobolectricTestRunner;
  import org.robolectric.annotation.Config;
  import org.robolectric.RuntimeEnvironment;
  
  import java.util.Arrays;
  
  import static junit.framework.Assert.assertEquals;
  import static junit.framework.Assert.assertNotNull;
  import static junit.framework.Assert.assertNull;
  
  @Config(sdk = 28)
  
  /**
   * Created by dyoung on 2/6/15.
   * This test verifies that a beacon can be parsed that uses a Gatt UUID
   */
  @RunWith(RobolectricTestRunner.class)
  public class GattBeaconTest {
      @Test
      public void testDetectsGattBeacon() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          System.err.println("verbose logging:"+LogManager.isVerboseLoggingEnabled());
          byte[] bytes = hexStringToByteArray("020106030334121516341200e72f234454f4911ba9ffa6000000000001000000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=1234,m:2-2=00,p:3-3:-41,i:4-13,i:14-19");
          assertNotNull("Service uuid parsed should not be null", parser.getServiceUuid());
          Beacon gattBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("GattBeacon should be not null if parsed successfully", gattBeacon);
          assertEquals("id1 should be parsed", "0x2f234454f4911ba9ffa6", gattBeacon.getId1().toString());
          assertEquals("id2 should be parsed", "0x000000000001", gattBeacon.getId2().toString());
          assertEquals("serviceUuid should be parsed", 0x1234, gattBeacon.getServiceUuid());
          assertEquals("txPower should be parsed", -66, gattBeacon.getTxPower());
      }
  
      @Test
      public void testDetectsGattBeacon2MaxLength() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          byte[] bytes = hexStringToByteArray("020106030334121616341210ec007261646975736e6574776f726b7373070000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=1234,m:2-2=10,p:3-3:-41,i:4-20v");
          Beacon gattBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("GattBeacon should be not null if parsed successfully", gattBeacon);
          assertEquals("GattBeacon identifier length should be proper length",
                  17,
                  gattBeacon.getId1().toByteArray().length);
  
      }
  
      @Test
      public void testDetectsGattBeacon2WithShortIdentifier() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          LogManager.d("GattBeaconTest", "Parsing short packet");
          byte[] bytes = hexStringToByteArray("020106030334121516341210ec007261646975736e6574776f726b7307000000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=1234,m:2-2=10,p:3-3:-41,i:4-20v");
          Beacon gattBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("GattBeacon should be not null if parsed successfully", gattBeacon);
          assertEquals("GattBeacon identifier length should be adjusted smaller if packet is short",
                       16,
                       gattBeacon.getId1().toByteArray().length);
          assertEquals("GattBeacon identifier should have proper first byte",
                  (byte)0x00,
                  gattBeacon.getId1().toByteArray()[0]);
          assertEquals("GattBeacon identifier should have proper second to last byte",
                  (byte) 0x73,
                  gattBeacon.getId1().toByteArray()[14]);
          assertEquals("GattBeacon identifier should have proper last byte",
                  (byte)0x07,
                  gattBeacon.getId1().toByteArray()[15]);
  
      }
  
  
      @Test
      public void testDetectsEddystoneUID() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          byte[] bytes = hexStringToByteArray("0201060303aafe1516aafe00e700010203040506070809010203040506000000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT);
          Beacon eddystoneUidBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("Eddystone-UID should be not null if parsed successfully", eddystoneUidBeacon);
      }
  
  
      @Test
      public void testDetectsGattBeaconWithCnn() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          LogManager.d("GattBeaconTest", "Parsing short packet");
          byte[] bytes = hexStringToByteArray("020106030334120a16341210ed00636e6e070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=1234,m:2-2=10,p:3-3:-41,i:4-20v");
          LogManager.d("xxx", "------");
          Beacon gattBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("GattBeacon should be not null if parsed successfully", gattBeacon);
          assertEquals("GattBeacon identifier length should be adjusted smaller if packet is short",
                  5,
                  gattBeacon.getId1().toByteArray().length);
      }
  
      @Test
      public void testBeaconAdvertisingBytes() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          Context context = RuntimeEnvironment.application;
  
  
          Beacon beacon = new Beacon.Builder()
                  .setId1("0x454452e29735323d81c0")
                  .setId2("0x060504030201")
                  .setDataFields(Arrays.asList(0x25l))
                  .setTxPower(-59)
                  .build();
          // TODO: need to use something other than the d: prefix here for an internally generated field
          BeaconParser beaconParser = new BeaconParser()
                  .setBeaconLayout("s:0-1=0123,m:2-2=00,d:3-3,p:4-4,i:5-14,i:15-20");
          byte[] data = beaconParser.getBeaconAdvertisementData(beacon);
  //        BeaconTransmitter beaconTransmitter = new BeaconTransmitter(context, beaconParser);
          // TODO: can't actually start transmitter here because Robolectric does not support API 21
  
          assertEquals("Data should be 19 bytes long", 19, data.length);
          String byteString = "";
          for (int i = 0; i < data.length; i++) {
              byteString += String.format("%02X", data[i]);
              byteString += " ";
          }
          assertEquals("Advertisement bytes should be as expected", "00 25 C5 45 44 52 E2 97 35 32 3D 81 C0 06 05 04 03 02 01 ", byteString);
      }
  
      @Test
      public void testDetectsUriBeacon() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          //"https://goo.gl/hqBXE1"
          byte[] bytes = {2, 1, 4, 3, 3, (byte) 216, (byte) 254, 19, 22, (byte) 216, (byte) 254, 0, (byte) 242, 3, 103, 111, 111, 46, 103, 108, 47, 104, 113, 66, 88, 69, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=fed8,m:2-2=00,p:3-3:-41,i:4-21v");
          LogManager.d("xxx", "------");
          Beacon uriBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("UriBeacon should be not null if parsed successfully", uriBeacon);
          assertEquals("UriBeacon identifier length should be correct",
                  14,
                  uriBeacon.getId1().toByteArray().length);
          String urlString = UrlBeaconUrlCompressor.uncompress(uriBeacon.getId1().toByteArray());
          assertEquals("URL should be decompressed successfully", "https://goo.gl/hqBXE1", urlString);
      }
  
  
      @Test
      public void doesNotCrashOnMalformedEddystoneBeacon() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          LogManager.setLogger(Loggers.verboseLogger());
          LogManager.setVerboseLoggingEnabled(true);
          LogManager.d("GattBeaconTest", "Parsing malformed packet");
          byte[] bytes = hexStringToByteArray("0201060303aafe0416aafe100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
          BeaconParser parser = new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v");
          LogManager.d("xxx", "------");
          Beacon gattBeacon = parser.fromScanData(bytes, -55, null, 123456L);
          assertNull("GattBeacon should be null when not parsed successfully", gattBeacon);
      }
  
  
  
  
      public static byte[] hexStringToByteArray(String s) {
          int len = s.length();
          byte[] data = new byte[len / 2];
          for (int i = 0; i < len; i += 2) {
              data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                      + Character.digit(s.charAt(i+1), 16));
          }
          return data;
      }
  
  }
  