public void testTrackCharge() {
    final List<JSONObject> messages = new ArrayList<JSONObject>();
    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          public void eventsMessage(EventDescription heard) {
            throw new RuntimeException("Should not be called during this test");
          }

          @Override
          public void peopleMessage(JSONObject heard) {
            messages.add(heard);
          }
        };

    class ListeningAPI extends TestUtils.CleanMixpanelAPI {
      public ListeningAPI(Context c, Future<SharedPreferences> referrerPrefs, String token) {
        super(c, referrerPrefs, token);
      }

      @Override
      protected AnalyticsMessages getAnalyticsMessages() {
        return listener;
      }
    }

    MixpanelAPI api = new ListeningAPI(getContext(), mMockPreferences, "TRACKCHARGE TEST TOKEN");
    api.getPeople().identify("TRACKCHARGE PERSON");

    JSONObject props;
    try {
      props = new JSONObject("{'$time':'Should override', 'Orange':'Banana'}");
    } catch (JSONException e) {
      throw new RuntimeException("Can't construct fixture for trackCharge test");
    }

    api.getPeople().trackCharge(2.13, props);
    assertEquals(messages.size(), 1);

    JSONObject message = messages.get(0);

    try {
      JSONObject append = message.getJSONObject("$append");
      JSONObject newTransaction = append.getJSONObject("$transactions");
      assertEquals(newTransaction.optString("Orange"), "Banana");
      assertEquals(newTransaction.optString("$time"), "Should override");
      assertEquals(newTransaction.optDouble("$amount"), 2.13);
    } catch (JSONException e) {
      fail("Transaction message had unexpected layout:\n" + message.toString());
    }
  }
  public static void createUser(android.content.Context context, Pessoa pessoa) {

    MixpanelAPI mixpanel = MixpanelAPI.getInstance(context, MIXPANEL_TOKEN);

    mixpanel.getPeople().identify(pessoa.getUid());
    mixpanel.getPeople().initPushHandling(CommonUtilities.SENDER_ID);

    mixpanel.getPeople().set("Nome", pessoa.getNome());
    mixpanel.getPeople().set("Cidade", pessoa.getCidade());
    mixpanel.getPeople().set("Pais", pessoa.getPais());
    mixpanel.getPeople().set("Sexo", pessoa.getSexo());
    mixpanel.getPeople().set("Aniversario", pessoa.getAniversario());
    mixpanel.getPeople().set("Status de relacionamento", pessoa.getRelationship_status());
  }
  public void testDecideUpdatesWithIdentityChanges() {
    MixpanelAPI metrics =
        new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "Identity Changes Token");

    assertFalse(metrics.canUpdate());

    metrics.getPeople().identify(null);
    assertFalse(metrics.canUpdate());

    metrics.getPeople().identify("NOT NULL");
    assertTrue(metrics.canUpdate());

    metrics.getPeople().identify("Also Not Null");
    assertTrue(metrics.canUpdate());

    metrics.getPeople().identify(null);
    assertFalse(metrics.canUpdate());

    metrics.getPeople().identify("Not Null Again");
    assertTrue(metrics.canUpdate());
  }
  public void testIdentifyAndGetDistinctId() {
    MixpanelAPI metrics =
        new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "Identify Test Token");

    String generatedId = metrics.getDistinctId();
    assertNotNull(generatedId);

    String emptyId = metrics.getPeople().getDistinctId();
    assertNull(emptyId);

    metrics.identify("Events Id");
    String setId = metrics.getDistinctId();
    assertEquals("Events Id", setId);

    String stillEmpty = metrics.getPeople().getDistinctId();
    assertNull(stillEmpty);

    metrics.getPeople().identify("People Id");
    String unchangedId = metrics.getDistinctId();
    assertEquals("Events Id", unchangedId);

    String setPeopleId = metrics.getPeople().getDistinctId();
    assertEquals("People Id", setPeopleId);
  }
  public void testIdentifyAfterSet() {
    final List<JSONObject> messages = new ArrayList<JSONObject>();

    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          public void peopleMessage(JSONObject heard) {
            messages.add(heard);
          }
        };

    MixpanelAPI mixpanel =
        new TestUtils.CleanMixpanelAPI(
            getContext(), mMockPreferences, "TEST TOKEN testIdentifyAfterSet") {
          @Override
          protected AnalyticsMessages getAnalyticsMessages() {
            return listener;
          }
        };

    MixpanelAPI.People people = mixpanel.getPeople();
    people.increment("the prop", 0L);
    people.append("the prop", 1);
    people.set("the prop", 2);
    people.increment("the prop", 3L);
    people.increment("the prop", 4);
    people.append("the prop", 5);
    people.append("the prop", 6);
    people.identify("Personal Identity");

    assertEquals(messages.size(), 7);
    try {
      for (JSONObject message : messages) {
        String distinctId = message.getString("$distinct_id");
        assertEquals(distinctId, "Personal Identity");
      }

      assertTrue(messages.get(0).has("$add"));
      assertTrue(messages.get(1).has("$append"));
      assertTrue(messages.get(2).has("$set"));
      assertTrue(messages.get(3).has("$add"));
      assertTrue(messages.get(4).has("$add"));
    } catch (JSONException e) {
      fail("Unexpected JSON error in stored messages.");
    }
  }
 /**
  * Tracks a charge (with properties) for the identified user.
  *
  * @param charge
  * @param properties
  */
 @ReactMethod
 public void peopleTrackChargeWithProperties(double charge, ReadableMap properties) {
   mixpanel.getPeople().trackCharge(charge, this.readableMapToJson(properties));
 }
 /**
  * Tracks a charge for the identified user.
  *
  * @param charge
  */
 @ReactMethod
 public void peopleTrackCharge(double charge) {
   mixpanel.getPeople().trackCharge(charge, null);
 }
 /**
  * Increments properties for the identified user.
  *
  * @param properties
  */
 @ReactMethod
 public void peopleIncrement(ReadableMap properties) {
   mixpanel.getPeople().increment(this.readableMapToNumberMap(properties));
 }
 @ReactMethod
 public void set(ReadableMap properties) {
   mixpanel.getPeople().set(this.readableMapToJson(properties));
 }
 /**
  * Ability to send push notifications on Android devices.
  *
  * @param projectNum
  */
 @ReactMethod
 public void initPushHandling(String projectNum) {
   mixpanel.getPeople().initPushHandling(projectNum);
 }
 /**
  * Sets a user ID to identify events by.
  *
  * @param id
  */
 @ReactMethod
 public void identify(String id) {
   mixpanel.identify(id);
   mixpanel.getPeople().identify(id);
 }
  public void testPersistence() {
    MixpanelAPI metricsOne = new MixpanelAPI(getContext(), mMockPreferences, "SAME TOKEN");
    metricsOne.clearPreferences();

    JSONObject props;
    try {
      props = new JSONObject("{ 'a' : 'value of a', 'b' : 'value of b' }");
    } catch (JSONException e) {
      throw new RuntimeException("Can't construct fixture for super properties test.");
    }

    metricsOne.clearSuperProperties();
    metricsOne.registerSuperProperties(props);
    metricsOne.identify("Expected Events Identity");
    metricsOne.getPeople().identify("Expected People Identity");

    // We exploit the fact that any metrics object with the same token
    // will get their values from the same persistent store.

    final List<Object> messages = new ArrayList<Object>();
    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          public void eventsMessage(EventDescription heard) {
            messages.add(heard);
          }

          @Override
          public void peopleMessage(JSONObject heard) {
            messages.add(heard);
          }
        };

    class ListeningAPI extends MixpanelAPI {
      public ListeningAPI(Context c, Future<SharedPreferences> prefs, String token) {
        super(c, prefs, token);
      }

      @Override
      protected AnalyticsMessages getAnalyticsMessages() {
        return listener;
      }
    }

    MixpanelAPI differentToken =
        new ListeningAPI(getContext(), mMockPreferences, "DIFFERENT TOKEN");

    differentToken.track("other event", null);
    differentToken.getPeople().set("other people prop", "Word"); // should be queued up.

    assertEquals(1, messages.size());

    AnalyticsMessages.EventDescription eventMessage =
        (AnalyticsMessages.EventDescription) messages.get(0);

    try {
      JSONObject eventProps = eventMessage.getProperties();
      String sentId = eventProps.getString("distinct_id");
      String sentA = eventProps.optString("a");
      String sentB = eventProps.optString("b");

      assertFalse("Expected Events Identity".equals(sentId));
      assertEquals("", sentA);
      assertEquals("", sentB);
    } catch (JSONException e) {
      fail("Event message has an unexpected shape " + e);
    }

    messages.clear();

    MixpanelAPI metricsTwo = new ListeningAPI(getContext(), mMockPreferences, "SAME TOKEN");

    metricsTwo.track("eventname", null);
    metricsTwo.getPeople().set("people prop name", "Indeed");

    assertEquals(2, messages.size());

    eventMessage = (AnalyticsMessages.EventDescription) messages.get(0);
    JSONObject peopleMessage = (JSONObject) messages.get(1);

    try {
      JSONObject eventProps = eventMessage.getProperties();
      String sentId = eventProps.getString("distinct_id");
      String sentA = eventProps.getString("a");
      String sentB = eventProps.getString("b");

      assertEquals("Expected Events Identity", sentId);
      assertEquals("value of a", sentA);
      assertEquals("value of b", sentB);
    } catch (JSONException e) {
      fail("Event message has an unexpected shape " + e);
    }

    try {
      String sentId = peopleMessage.getString("$distinct_id");
      assertEquals("Expected People Identity", sentId);
    } catch (JSONException e) {
      fail("Event message has an unexpected shape: " + peopleMessage.toString());
    }
  }
  public void testMessageQueuing() {
    final BlockingQueue<String> messages = new LinkedBlockingQueue<String>();
    final SynchronizedReference<Boolean> okToDecide = new SynchronizedReference<Boolean>();
    okToDecide.set(false);

    final MPDbAdapter mockAdapter =
        new MPDbAdapter(getContext()) {
          @Override
          public int addJSON(JSONObject message, MPDbAdapter.Table table) {
            try {
              messages.put("TABLE " + table.getName());
              messages.put(message.toString());
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }

            return super.addJSON(message, table);
          }
        };
    mockAdapter.cleanupEvents(Long.MAX_VALUE, MPDbAdapter.Table.EVENTS);
    mockAdapter.cleanupEvents(Long.MAX_VALUE, MPDbAdapter.Table.PEOPLE);

    final ServerMessage mockPoster =
        new ServerMessage() {
          @Override
          public byte[] performRequest(String endpointUrl, List<NameValuePair> nameValuePairs) {
            final boolean decideIsOk = okToDecide.get();
            if (null == nameValuePairs) {
              if (decideIsOk) {
                assertEquals(
                    "DECIDE_ENDPOINT?version=1&lib=android&token=Test+Message+Queuing&distinct_id=new+person",
                    endpointUrl);
              } else {
                fail(
                    "User is unidentified, we shouldn't be checking decide. (URL WAS "
                        + endpointUrl
                        + ")");
              }
              return TestUtils.bytes("{}");
            }

            assertEquals(nameValuePairs.get(0).getName(), "data");
            final String decoded = Base64Coder.decodeString(nameValuePairs.get(0).getValue());

            try {
              messages.put("SENT FLUSH " + endpointUrl);
              messages.put(decoded);
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }

            return TestUtils.bytes("1\n");
          }
        };

    final MPConfig mockConfig =
        new MPConfig(new Bundle()) {
          @Override
          public int getFlushInterval() {
            return -1;
          }

          @Override
          public int getBulkUploadLimit() {
            return 40;
          }

          @Override
          public String getEventsEndpoint() {
            return "EVENTS_ENDPOINT";
          }

          @Override
          public String getPeopleEndpoint() {
            return "PEOPLE_ENDPOINT";
          }

          @Override
          public String getDecideEndpoint() {
            return "DECIDE_ENDPOINT";
          }
        };

    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          protected MPDbAdapter makeDbAdapter(Context context) {
            return mockAdapter;
          }

          @Override
          protected MPConfig getConfig(Context context) {
            return mockConfig;
          }

          @Override
          protected ServerMessage getPoster() {
            return mockPoster;
          }
        };

    MixpanelAPI metrics =
        new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "Test Message Queuing") {
          @Override
          protected AnalyticsMessages getAnalyticsMessages() {
            return listener;
          }
        };

    // Test filling up the message queue
    for (int i = 0; i < mockConfig.getBulkUploadLimit() - 1; i++) {
      metrics.track("frequent event", null);
    }

    metrics.track("final event", null);
    String expectedJSONMessage = "<No message actually received>";

    try {
      for (int i = 0; i < mockConfig.getBulkUploadLimit() - 1; i++) {
        String messageTable = messages.poll(1, TimeUnit.SECONDS);
        assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), messageTable);

        expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
        JSONObject message = new JSONObject(expectedJSONMessage);
        assertEquals("frequent event", message.getString("event"));
      }

      String messageTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), messageTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject message = new JSONObject(expectedJSONMessage);
      assertEquals("final event", message.getString("event"));

      String messageFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH EVENTS_ENDPOINT", messageFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray bigFlush = new JSONArray(expectedJSONMessage);
      assertEquals(mockConfig.getBulkUploadLimit(), bigFlush.length());

      metrics.track("next wave", null);
      metrics.flush();

      String nextWaveTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), nextWaveTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject nextWaveMessage = new JSONObject(expectedJSONMessage);
      assertEquals("next wave", nextWaveMessage.getString("event"));

      String manualFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH EVENTS_ENDPOINT", manualFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray nextWave = new JSONArray(expectedJSONMessage);
      assertEquals(1, nextWave.length());

      JSONObject nextWaveEvent = nextWave.getJSONObject(0);
      assertEquals("next wave", nextWaveEvent.getString("event"));

      okToDecide.set(true);
      metrics.getPeople().identify("new person");
      metrics.getPeople().set("prop", "yup");
      metrics.flush();

      String peopleTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.PEOPLE.getName(), peopleTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject peopleMessage = new JSONObject(expectedJSONMessage);

      assertEquals("new person", peopleMessage.getString("$distinct_id"));
      assertEquals("yup", peopleMessage.getJSONObject("$set").getString("prop"));

      String peopleFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH PEOPLE_ENDPOINT", peopleFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray peopleSent = new JSONArray(expectedJSONMessage);
      assertEquals(1, peopleSent.length());

    } catch (InterruptedException e) {
      fail("Expected a log message about mixpanel communication but did not recieve it.");
    } catch (JSONException e) {
      fail(
          "Expected a JSON object message and got something silly instead: " + expectedJSONMessage);
    }
  }
  public void testPeopleOperations() throws JSONException {
    final List<JSONObject> messages = new ArrayList<JSONObject>();

    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          public void peopleMessage(JSONObject heard) {
            messages.add(heard);
          }
        };

    MixpanelAPI mixpanel =
        new TestUtils.CleanMixpanelAPI(
            getContext(), mMockPreferences, "TEST TOKEN testIdentifyAfterSet") {
          @Override
          protected AnalyticsMessages getAnalyticsMessages() {
            return listener;
          }
        };

    assertFalse(mixpanel.canUpdate());

    mixpanel.getPeople().identify("TEST IDENTITY");

    mixpanel.getPeople().set("SET NAME", "SET VALUE");
    mixpanel.getPeople().increment("INCREMENT NAME", 1);
    mixpanel.getPeople().append("APPEND NAME", "APPEND VALUE");
    mixpanel.getPeople().setOnce("SET ONCE NAME", "SET ONCE VALUE");
    mixpanel.getPeople().union("UNION NAME", new JSONArray("[100]"));
    mixpanel.getPeople().unset("UNSET NAME");
    mixpanel.getPeople().trackCharge(100, new JSONObject("{\"name\": \"val\"}"));
    mixpanel.getPeople().clearCharges();
    mixpanel.getPeople().deleteUser();

    JSONObject setMessage = messages.get(0).getJSONObject("$set");
    assertEquals("SET VALUE", setMessage.getString("SET NAME"));

    JSONObject addMessage = messages.get(1).getJSONObject("$add");
    assertEquals(1, addMessage.getInt("INCREMENT NAME"));

    JSONObject appendMessage = messages.get(2).getJSONObject("$append");
    assertEquals("APPEND VALUE", appendMessage.get("APPEND NAME"));

    JSONObject setOnceMessage = messages.get(3).getJSONObject("$set_once");
    assertEquals("SET ONCE VALUE", setOnceMessage.getString("SET ONCE NAME"));

    JSONObject unionMessage = messages.get(4).getJSONObject("$union");
    JSONArray unionValues = unionMessage.getJSONArray("UNION NAME");
    assertEquals(1, unionValues.length());
    assertEquals(100, unionValues.getInt(0));

    JSONArray unsetMessage = messages.get(5).getJSONArray("$unset");
    assertEquals(1, unsetMessage.length());
    assertEquals("UNSET NAME", unsetMessage.get(0));

    JSONObject trackChargeMessage = messages.get(6).getJSONObject("$append");
    JSONObject transaction = trackChargeMessage.getJSONObject("$transactions");
    assertEquals(100.0d, transaction.getDouble("$amount"));

    JSONArray clearChargesMessage = messages.get(7).getJSONArray("$unset");
    assertEquals(1, clearChargesMessage.length());
    assertEquals("$transactions", clearChargesMessage.getString(0));

    assertTrue(messages.get(8).has("$delete"));
  }