TEST(TestIRPanasonicAcClass, SetAndGetModel) {
  IRPanasonicAc pana(0);
  EXPECT_EQ(kPanasonicJke, pana.getModel());
  pana.setModel(kPanasonicDke);
  EXPECT_EQ(kPanasonicDke, pana.getModel());
  pana.setModel(kPanasonicLke);
  EXPECT_EQ(kPanasonicLke, pana.getModel());
  pana.setModel(kPanasonicNke);
  EXPECT_EQ(kPanasonicNke, pana.getModel());
  pana.setModel(kPanasonicUnknown);  // shouldn't change.
  EXPECT_EQ(kPanasonicNke, pana.getModel());
  pana.setModel((panasonic_ac_remote_model_t)255);  // shouldn't change.
  EXPECT_EQ(kPanasonicNke, pana.getModel());
  pana.setModel(kPanasonicJke);
  EXPECT_EQ(kPanasonicJke, pana.getModel());

  // This state tickled a bug in getModel(). Should read as a JKE.
  uint8_t jkeState[27] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
                          0x20, 0xE0, 0x04, 0x00, 0x32, 0x2E, 0x80, 0xA2, 0x00,
                          0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x74};
  pana.setModel(kPanasonicDke);  // Make sure it isn't somehow set to JKE
  pana.setRaw(jkeState);
  EXPECT_EQ(kPanasonicJke, pana.getModel());
  EXPECT_STATE_EQ(jkeState, pana.getRaw(), kPanasonicAcBits);

  // This state tickled a bug in getModel(). Should read as CKP.
  uint8_t ckpState[27] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
                          0x20, 0xE0, 0x04, 0x00, 0x67, 0x2E, 0x80, 0xAF, 0x00,
                          0xC0, 0x6B, 0x98, 0x10, 0x00, 0x81, 0x64, 0x05, 0x87};
  pana.setModel(kPanasonicDke);  // Make sure it isn't somehow set to CKP
  pana.setRaw(ckpState);
  EXPECT_EQ(kPanasonicCkp, pana.getModel());
  EXPECT_STATE_EQ(ckpState, pana.getRaw(), kPanasonicAcBits);
}
// Decode normal "synthetic" messages.
TEST(TestDecodeHaierAC, NormalDecodeWithStrict) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  uint8_t expectedState[HAIER_AC_STATE_LENGTH] = {
      0xA5, 0x01, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0xA7};
  // With the specific decoder.
  irsend.reset();
  irsend.sendHaierAC(expectedState);
  irsend.makeDecodeResult();
  ASSERT_TRUE(irrecv.decodeHaierAC(&irsend.capture, HAIER_AC_BITS, true));
  EXPECT_EQ(HAIER_AC, irsend.capture.decode_type);
  EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);

  // With the all the decoders.
  irsend.reset();
  irsend.sendHaierAC(expectedState);
  irsend.makeDecodeResult();
  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  EXPECT_EQ(HAIER_AC, irsend.capture.decode_type);
  EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}
TEST(TestSharpAcClass, ReconstructKnownState) {
  IRSharpAc ac(0);
  ac.begin();

  uint8_t on_auto_auto[kSharpAcStateLength] = {
      0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0,
      0x01};
  ac.on();
  ac.setMode(kSharpAcAuto);
  ac.setTemp(kSharpAcMinTemp);
  ac.setFan(kSharpAcFanAuto);
  EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits);
  EXPECT_EQ("Power: On, Mode: 0 (AUTO), Temp: 15C, Fan: 2 (AUTO)",
            ac.toString());

  uint8_t cool_auto_28[kSharpAcStateLength] = {
      0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
      0x51};
  ac.stateReset();
  ac.on();
  ac.setMode(kSharpAcCool);
  ac.setTemp(28);
  ac.setFan(kSharpAcFanAuto);
  EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 2 (AUTO)",
            ac.toString());
  EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits);
}
// Build a known good message from scratch.
TEST(TestIRWhirlpoolAcClass, MessageConstruction) {
  // Real example captured from a remote. (ref: RealTimerExample)
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07,
      0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05};
  IRWhirlpoolAc ac(0);
  ac.setModel(DG11J13A);
  ac.setTemp(25);
  ac.setPowerToggle(false);
  ac.setMode(kWhirlpoolAcDry);
  ac.setFan(kWhirlpoolAcFanAuto);
  ac.setSwing(false);
  ac.setLight(true);
  ac.setClock(7 * 60 + 35);
  ac.setOnTimer(7 * 60 + 40);
  ac.setOffTimer(8 * 60 + 5);
  ac.enableOffTimer(true);
  ac.setSleep(false);
  ac.setSuper(false);
  ac.enableOnTimer(true);

  EXPECT_EQ(
      "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, "
      "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, "
      "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)",
      ac.toString());
  EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits);
}
// Decode synthetic Panasonic AC message.
TEST(TestDecodePanasonicAC, SyntheticExample) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Data from Issue #525
  uint8_t expectedState[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00,
      0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};

  irsend.sendPanasonicAC(expectedState);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);

  IRPanasonicAc pana(0);
  pana.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 4 (JKE), Power: Off, Mode: 3 (COOL), Temp: 25C, "
      "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), Quiet: Off, "
      "Powerful: Off, Clock: 0:00, On Timer: Off, Off Timer: Off",
      pana.toString());
}
TEST(TestIRPanasonicAcClass, ChecksumCalculation) {
  IRPanasonicAc pana(0);

  const uint8_t originalstate[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00,
      0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};
  uint8_t examplestate[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00,
      0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};

  EXPECT_TRUE(IRPanasonicAc::validChecksum(examplestate));
  EXPECT_EQ(0x83, IRPanasonicAc::calcChecksum(examplestate));

  examplestate[kPanasonicAcStateLength - 1] = 0x0;  // Set incoorect checksum.
  EXPECT_FALSE(IRPanasonicAc::validChecksum(examplestate));
  EXPECT_EQ(0x83, IRPanasonicAc::calcChecksum(examplestate));
  pana.setRaw(examplestate);
  // Extracting the state from the object should have a correct checksum.
  EXPECT_TRUE(IRPanasonicAc::validChecksum(pana.getRaw()));
  EXPECT_STATE_EQ(originalstate, pana.getRaw(), kPanasonicAcBits);
  examplestate[kPanasonicAcStateLength - 1] = 0x83;  // Restore old checksum.

  // Change the state to force a different checksum.
  examplestate[6] = 0x01;  // Should increase checksum by 1.
  EXPECT_FALSE(IRPanasonicAc::validChecksum(examplestate));
  EXPECT_EQ(0x84, IRPanasonicAc::calcChecksum(examplestate));
}
TEST(TestIRWhirlpoolAcClass, SetAndGetRaw) {
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
      0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
  IRWhirlpoolAc ac(0);
  ac.setRaw(expectedState);
  EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits);
}
// Decode normal Panasonic AC messages.
TEST(TestDecodePanasonicAC, RealExample) {
  IRsendTest irsend(4);
  IRrecv irrecv(4);
  irsend.begin();

  // Data from Issue #525
  uint16_t rawData[439] = {
      3582, 1686, 488, 378,  488, 1238, 488, 378,  488, 378,  488, 378,
      488,  378,  488, 378,  488, 384,  488, 378,  488, 378,  488, 378,
      488,  378,  488, 378,  488, 1242, 486, 378,  488, 384,  488, 378,
      488,  378,  488, 380,  486, 382,  484, 382,  484, 1264, 464, 1266,
      460,  1272, 462, 378,  488, 406,  460, 1266, 462, 380,  488, 382,
      484,  388,  478, 406,  462, 410,  462, 404,  462, 406,  462, 396,
      470,  406,  462, 404,  462, 406,  460, 404,  462, 410,  462, 404,
      462,  404,  462, 406,  464, 406,  462, 404,  462, 406,  462, 404,
      462,  410,  462, 404,  462, 406,  462, 404,  462, 404,  462, 404,
      462,  406,  460, 406,  462, 410,  462, 404,  462, 1264, 484, 1244,
      486,  382,  482, 382,  486, 382,  486, 378,  486, 382,  488, 9924,
      3554, 1686, 488, 378,  490, 1240, 486, 378,  488, 378,  488, 378,
      488,  378,  488, 382,  484, 386,  486, 378,  488, 382,  486, 378,
      488,  382,  486, 382,  484, 1242, 486, 380,  488, 386,  484, 382,
      486,  380,  486, 382,  486, 380,  486, 380,  486, 1242, 486, 1242,
      484,  1248, 484, 380,  488, 382,  484, 1242, 486, 382,  484, 382,
      484,  382,  484, 382,  486, 386,  484, 382,  486, 382,  484, 382,
      486,  382,  486, 380,  484, 382,  486, 382,  488, 380,  486, 382,
      484,  380,  462, 406,  488, 376,  484, 1246, 482, 1246, 460, 404,
      480,  392,  484, 386,  482, 1244, 484, 382,  484, 382,  484, 1242,
      482,  1244, 484, 382,  464, 410,  460, 404,  462, 406,  462, 404,
      462,  404,  470, 396,  462, 406,  462, 404,  462, 1286, 460, 1268,
      458,  1268, 460, 1266, 460, 1266, 460, 406,  460, 1266, 462, 406,
      460,  1272, 462, 406,  460, 406,  460, 406,  460, 406,  462, 404,
      462,  406,  460, 406,  462, 410,  462, 404,  462, 406,  460, 406,
      460,  406,  462, 404,  462, 406,  460, 406,  460, 410,  462, 406,
      460,  1268, 460, 1266, 460, 404,  460, 406,  462, 406,  460, 406,
      460,  412,  456, 410,  460, 410,  438, 428,  460, 410,  456, 410,
      456,  1272, 436, 1288, 438, 434,  438, 428,  438, 428,  438, 428,
      438,  428,  438, 428,  438, 428,  438, 428,  438, 434,  438, 428,
      438,  428,  438, 428,  438, 428,  438, 428,  440, 428,  438, 428,
      438,  432,  438, 428,  438, 428,  438, 428,  438, 428,  438, 428,
      438,  428,  438, 430,  438, 1294, 438, 428,  438, 428,  438, 428,
      438,  428,  438, 428,  438, 428,  438, 428,  438, 434,  438, 428,
      438,  1288, 438, 1290, 438, 428,  438, 428,  438, 428,  438, 428,
      438,  432,  438, 1288, 438, 1290, 438, 430,  438, 428,  438, 428,
      438,  428,  438, 428,  438, 1292, 438};
  uint8_t expectedState[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00,
      0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};

  irsend.sendRaw(rawData, 439, kPanasonicFreq);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);
}
//
// Test for CKP model / see issue #544
TEST(TestDecodePanasonicAC, CkpModelSpecifics) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Data from Issue #544
  uint8_t ckpPowerfulOn[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x4E, 0x2E, 0x80, 0xAF, 0x00,
      0x00, 0x0E, 0xE0, 0x11, 0x00, 0x01, 0x00, 0x06, 0xB7};
  uint8_t ckpQuietOn[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x4E, 0x2E, 0x80, 0xAF, 0x00,
      0x00, 0x0E, 0xE0, 0x30, 0x00, 0x01, 0x00, 0x06, 0xD6};

  irsend.sendPanasonicAC(ckpPowerfulOn);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(ckpPowerfulOn, irsend.capture.state, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);

  IRPanasonicAc pana(0);
  pana.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 5 (CKP), Power: Off, Mode: 4 (HEAT), Temp: 23C, "
      "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), Quiet: Off, "
      "Powerful: On, Clock: 0:00, On Timer: 0:00, Off Timer: 0:00",
      pana.toString());

  pana.setQuiet(true);
  EXPECT_FALSE(pana.getPowerful());
  EXPECT_TRUE(pana.getQuiet());
  EXPECT_EQ(kPanasonicCkp, pana.getModel());
  EXPECT_STATE_EQ(ckpQuietOn, pana.getRaw(), kPanasonicAcBits);

  pana.setPowerful(true);
  EXPECT_TRUE(pana.getPowerful());
  EXPECT_FALSE(pana.getQuiet());
  EXPECT_EQ(kPanasonicCkp, pana.getModel());
  EXPECT_STATE_EQ(ckpPowerfulOn, pana.getRaw(), kPanasonicAcBits);
}
// Decode a recorded example
TEST(TestDecodeWhirlpoolAC, RealExampleDecode) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Real WhirlpoolAC message.
  // Ref: https://github.com/markszabo/IRremoteESP8266/issues/509
  uint16_t rawData[343] = {
      8950, 4484, 598, 1642, 598, 1646, 594, 534,  594, 538,  602, 532,
      598,  540,  600, 542,  598, 1650, 600, 522,  598, 1644, 596, 1650,
      600,  532,  598, 538,  602, 536,  594, 548,  592, 538,  602, 518,
      600,  524,  596, 532,  598, 532,  598, 1654, 596, 544,  596, 544,
      596,  536,  594, 1644, 596, 528,  600, 528,  592, 538,  602, 1648,
      602,  1654, 596, 1664, 598, 534,  594, 526,  594, 530,  598, 528,
      602,  530,  600, 534,  596, 542,  598, 542,  598, 534,  596, 526,
      594,  530,  600, 528,  602, 530,  600, 534,  596, 542,  598, 544,
      596,  518,  602, 7916, 598, 1642, 598, 528,  600, 528,  602, 530,
      600,  1652, 598, 542,  598, 544,  596, 1654, 596, 1644, 596, 1648,
      602,  1644, 596, 1654, 596, 1656, 604, 536,  594, 548,  602, 528,
      600,  520,  600, 524,  596, 532,  598, 532,  596, 538,  602, 536,
      594,  546,  594, 538,  602, 518,  600, 524,  596, 532,  598, 532,
      598,  536,  594, 544,  596, 544,  596, 536,  594, 526,  592, 530,
      600,  528,  600, 530,  602, 532,  596, 542,  598, 542,  598, 534,
      596,  524,  596, 528,  600, 526,  592, 538,  592, 542,  598, 540,
      600,  540,  600, 530,  598, 522,  598, 526,  594, 534,  596, 534,
      594,  540,  602, 536,  592, 548,  592, 538,  600, 1636, 594, 1648,
      602,  1642, 598, 1652, 598, 538,  602, 1680, 570, 1662, 598, 1634,
      596,  7924, 600, 520,  598, 526,  592, 534,  596, 534,  596, 540,
      600,  536,  604, 538,  602, 530,  600, 520,  598, 1640, 600, 528,
      600,  530,  600, 534,  594, 544,  596, 544,  596, 534,  596, 526,
      594,  528,  600, 526,  594, 536,  592, 542,  598, 538,  602, 538,
      602,  528,  600, 520,  600, 524,  596, 530,  600, 532,  598, 534,
      596,  542,  598, 542,  598, 532,  598, 524,  596, 528,  602, 526,
      594,  536,  594, 540,  600, 536,  594, 548,  592, 538,  602, 518,
      602,  522,  596, 530,  600, 530,  600, 534,  596, 542,  598, 544,
      596,  534,  596, 524,  594, 1644, 596, 532,  596, 534,  596, 538,
      602,  536,  594, 546,  594, 520,  600};
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
      0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};

  irsend.reset();
  irsend.sendRaw(rawData, 343, 38000);
  irsend.makeDecodeResult();
  EXPECT_TRUE(irrecv.decode(&irsend.capture));
  EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
  EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  IRWhirlpoolAc ac(0);
  ac.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, "
      "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, "
      "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)",
      ac.toString());
}
TEST(TestDecodeWhirlpoolAC, RealTimerExample) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  irsend.reset();
  // Dehumidify timer on 7:40 off 8:05
  uint16_t rawData[343] = {
      9092, 4556, 604, 1664, 604, 1674, 630, 514,  630, 518,  628, 522,
      604,  550,  628, 530,  602, 1680, 630, 508,  630, 1644, 604, 1674,
      604,  544,  604, 548,  630, 524,  604, 554,  620, 530,  630, 506,
      602,  538,  602, 542,  604, 542,  604, 546,  630, 524,  602, 556,
      628,  518,  604, 1666, 632, 1644, 604, 540,  602, 546,  604, 1680,
      604,  1684, 604, 1686, 630, 520,  602, 534,  606, 538,  602, 540,
      604,  544,  604, 548,  602, 552,  630, 528,  602, 546,  602, 536,
      628,  510,  606, 540,  604, 544,  630, 522,  604, 554,  600, 554,
      602,  528,  602, 8032, 604, 1666, 604, 1668, 602, 1676, 630, 518,
      630,  520,  602, 550,  604, 554,  604, 1678, 630, 1640, 602, 1672,
      602,  542,  602, 544,  628, 522,  630, 1658, 604, 554,  628, 1652,
      630,  508,  602, 538,  630, 514,  630, 1652, 602, 546,  604, 550,
      602,  554,  602, 546,  630, 1638, 604, 536,  630, 1646, 602, 544,
      628,  522,  632, 524,  628, 528,  602, 1686, 594, 1666, 604, 1670,
      602,  1674, 632, 516,  604, 546,  638, 518,  622, 534,  628, 518,
      604,  532,  604, 536,  600, 550,  622, 1652, 630, 520,  602, 1684,
      602,  554,  602, 544,  630, 506,  628, 512,  602, 540,  628, 518,
      602,  550,  602, 552,  604, 554,  602, 544,  628, 1642, 602, 536,
      632,  1646, 630, 516,  602, 1680, 630, 1656, 604, 1688, 602, 1660,
      602,  8030, 604, 532,  604, 536,  604, 540,  602, 544,  628, 522,
      602,  552,  602, 556,  602, 544,  602, 1666, 630, 510,  602, 1674,
      604,  544,  628, 522,  602, 552,  630, 526,  628, 520,  602, 534,
      630,  510,  604, 540,  602, 544,  606, 544,  604, 550,  604, 554,
      602,  544,  604, 534,  602, 538,  602, 542,  604, 542,  604, 546,
      604,  550,  632, 526,  604, 544,  630, 506,  604, 536,  604, 540,
      628,  518,  602, 548,  604, 550,  604, 552,  630, 516,  602, 534,
      604,  536,  630, 512,  604, 544,  602, 548,  630, 524,  602, 554,
      602,  542,  604, 1666, 606, 532,  630, 1644, 602, 544,  630, 520,
      604,  550,  604, 554,  602, 526,  598};
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07,
      0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05};
  irsend.sendRaw(rawData, 343, 38000);
  irsend.makeDecodeResult();
  EXPECT_TRUE(irrecv.decode(&irsend.capture));
  EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
  EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  IRWhirlpoolAc ac(0);
  ac.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, "
      "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, "
      "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)",
      ac.toString());
}
// https://github.com/markszabo/IRremoteESP8266/issues/638#issue-421064165
TEST(TestDecodeSharpAc, SyntheticExample) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  // cool-auto-27.txt
  uint8_t expectedState[kSharpAcStateLength] = {
      0xAA, 0x5A, 0xCF, 0x10, 0xCC, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
      0x41};

  irsend.begin();
  irsend.reset();
  irsend.sendSharpAc(expectedState);
  irsend.makeDecodeResult();
  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(SHARP_AC, irsend.capture.decode_type);
  ASSERT_EQ(kSharpAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}
// Create and decode a short Panasonic AC message
TEST(TestDecodePanasonicAC, SyntheticShortMessage) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  uint8_t odourWash[kPanasonicAcStateShortLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06,
      0x02, 0x20, 0xE0, 0x04, 0x80, 0x9B, 0x32, 0x53};

  irsend.sendPanasonicAC(odourWash, kPanasonicAcStateShortLength);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcShortBits, irsend.capture.bits);
  EXPECT_STATE_EQ(odourWash, irsend.capture.state, irsend.capture.bits);
}
// Decode a real short Panasonic AC message
TEST(TestDecodePanasonicAC, RealExampleOfShortMessage) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Data from Issue #544 (Odour Wash)
  uint16_t rawData[263] = {
      3496, 1734, 506, 366,  448, 1294, 504, 368,  498, 374,  452, 418,
      448,  424,  444, 428,  450, 422,  446, 426,  450, 420,  448, 424,
      452,  418,  448, 422,  444, 1300, 498, 374,  504, 368,  448, 424,
      452,  418,  448, 424,  444, 428,  450, 422,  446, 1296, 500, 1242,
      502,  1242, 504, 368,  498, 374,  452, 1292, 504, 366,  450, 422,
      444,  426,  450, 420,  446, 424,  452, 418,  448, 424,  444, 428,
      450,  422,  444, 426,  450, 420,  446, 424,  452, 418,  448, 422,
      444,  428,  450, 422,  446, 426,  452, 420,  446, 426,  452, 418,
      448,  424,  442, 428,  448, 422,  444, 426,  450, 420,  446, 426,
      452,  418,  448, 424,  444, 428,  450, 422,  444, 1298, 500, 1244,
      500,  372,  444, 428,  450, 422,  446, 426,  452, 418,  448, 10020,
      3500, 1732, 498, 372,  452, 1290, 506, 366,  450, 422,  446, 426,
      452,  420,  448, 424,  452, 418,  448, 422,  444, 426,  450, 420,
      446,  426,  452, 420,  446, 1296, 500, 370,  444, 428,  450, 422,
      446,  426,  452, 420,  446, 424,  442, 428,  448, 1294, 502, 1240,
      504,  1238, 506, 366,  448, 422,  444, 1298, 498, 374,  452, 418,
      448,  424,  444, 428,  450, 422,  446, 426,  450, 420,  446, 424,
      452,  418,  448, 422,  444, 428,  450, 420,  446, 1298, 498, 1244,
      500,  1242, 502, 368,  446, 1298, 500, 1244, 500, 372,  444, 428,
      450,  1292, 504, 368,  446, 1296, 502, 370,  444, 426,  452, 1290,
      504,  1238, 506, 366,  450, 422,  446, 1298, 498, 1246, 500, 372,
      444,  428,  450, 1294, 452, 420,  446, 1296, 448, 422,  444};  // UNKNOWN
                                                                     // 1FB51F79

  uint8_t expectedState[kPanasonicAcStateShortLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06,
      0x02, 0x20, 0xE0, 0x04, 0x80, 0x9B, 0x32, 0x53};

  irsend.sendRaw(rawData, 263, kPanasonicFreq);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcShortBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}
// https://github.com/markszabo/IRremoteESP8266/issues/638#issue-421064165
TEST(TestDecodeSharpAc, RealExample) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  // cool-auto-27.txt
  uint16_t rawData[211] = {
      3804, 1892, 466, 486, 466, 1388, 466, 486, 466, 1386, 468, 486, 468, 1388,
      466, 486, 466, 1386, 468, 488, 466, 1388, 466, 488, 466, 1386, 468, 1388,
      466, 486, 466, 1388, 466, 486, 468, 1384, 468, 1388, 468, 1388, 466, 1388,
      466, 486, 468, 484, 468, 1386, 468, 1386, 468, 486, 466, 486, 468, 486,
      466, 488, 466, 1388, 466, 486, 466, 486, 468, 486, 466, 488, 466, 488,
      466, 1386, 468, 1388, 466, 486, 468, 486, 466, 1388, 464, 1388, 466, 1386,
      468, 486, 466, 486, 468, 486, 466, 1388, 468, 1384, 470, 486, 466, 486,
      468, 486, 468, 1386, 468, 486, 468, 486, 468, 486, 468, 1388, 466, 486,
      466, 486, 466, 486, 466, 488, 466, 486, 468, 486, 468, 486, 468, 486, 466,
      486, 466, 486, 466, 488, 466, 486, 466, 486, 466, 1388, 466, 486, 468,
      486, 466, 486, 468, 486, 468, 486, 466, 486, 466, 488, 466, 486, 466, 486,
      466, 488, 466, 486, 468, 1386, 468, 486, 466, 486, 466, 1390, 464, 488,
      466, 486, 468, 486, 468, 486, 466, 486, 466, 486, 466, 486, 468, 486, 468,
      486, 466, 486, 466, 1386, 468, 1390, 466, 1388, 466, 1388, 468, 486, 466,
      486, 468, 486, 466, 486, 466, 486, 466, 1390, 464, 486, 414};
      // UNKNOWN F2B82C78
  uint8_t expectedState[kSharpAcStateLength] = {
      0xAA, 0x5A, 0xCF, 0x10, 0xCC, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
      0x41};

  irsend.begin();
  irsend.reset();
  irsend.sendRaw(rawData, 211, 38000);
  irsend.makeDecodeResult();
  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(SHARP_AC, irsend.capture.decode_type);
  ASSERT_EQ(kSharpAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);

  IRSharpAc ac(0);
  ac.begin();
  ac.setRaw(irsend.capture.state);
  EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 27C, Fan: 2 (AUTO)",
            ac.toString());
}
TEST(TestDecodeWhirlpoolAC, Real26CFanAutoCoolingSwingOnClock1918) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  irsend.reset();
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x80, 0x82, 0x00, 0x00, 0x93, 0x12, 0x40, 0x00, 0x00,
      0x00, 0x00, 0xC3, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07};
  irsend.sendWhirlpoolAC(expectedState);
  irsend.makeDecodeResult();
  EXPECT_TRUE(irrecv.decode(&irsend.capture));
  EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
  EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  IRWhirlpoolAc ac(0);
  ac.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 1 (DG11J13A), Power toggle: Off, Mode: 2 (COOL), Temp: 26C, "
      "Fan: 0 (AUTO), Swing: On, Light: On, Clock: 19:18, On Timer: Off, "
      "Off Timer: Off, Sleep: Off, Super: Off, Command: 7 (SWING)",
      ac.toString());
}
// Tests for decodeWhirlpoolAC().
// Decode normal WhirlpoolAC messages.
TEST(TestDecodeWhirlpoolAC, SyntheticDecode) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Synthesised Normal WhirlpoolAC message.
  irsend.reset();
  uint8_t expectedState[kWhirlpoolAcStateLength] = {
      0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
      0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
  irsend.sendWhirlpoolAC(expectedState);
  irsend.makeDecodeResult();
  EXPECT_TRUE(irrecv.decode(&irsend.capture));
  EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
  EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  IRWhirlpoolAc ac(0);
  ac.setRaw(irsend.capture.state);
  EXPECT_EQ(
      "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, "
      "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, "
      "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)",
      ac.toString());
}
// Decode a "real" example message.
TEST(TestDecodeHaierAC, RealExample3) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  irsend.reset();
  // Data from Issue #404 captured by kuzin2006
  uint16_t rawData[149] = {3030, 3044, 3030, 4302, 578, 1692, 550, 582, 550,
      1706, 550, 714, 550, 582, 552, 1706, 550, 582, 550, 1836, 552, 1706, 578,
      1690, 552, 1704, 552, 714, 550, 1706, 552, 1706, 550, 582, 550, 714, 552,
      582, 550, 582, 578, 1690, 550, 714, 552, 582, 552, 582, 550, 582, 550,
      714, 550, 584, 550, 582, 550, 582, 578, 700, 552, 1706, 550, 582, 550,
      582, 552, 1836, 550, 582, 550, 582, 552, 1706, 550, 714, 578, 568, 552,
      582, 552, 582, 550, 714, 550, 1706, 550, 1706, 550, 582, 552, 712, 552,
      582, 580, 568, 550, 582, 550, 714, 550, 582, 550, 582, 550, 1706, 550,
      714, 550, 582, 550, 582, 578, 568, 552, 712, 552, 582, 550, 582, 550, 582,
      550, 712, 550, 584, 550, 582, 552, 582, 578, 722, 552, 1704, 550, 582,
      550, 1706, 550, 1862, 550, 1706, 550, 582, 550, 1704, 552, 582, 578};
  uint8_t expectedState[HAIER_AC_STATE_LENGTH] = {
      0xA5, 0xEC, 0x20, 0x09, 0x20, 0xC0, 0x20, 0x00, 0xBA};

  irsend.sendRaw(rawData, 149, 38000);
  irsend.makeDecodeResult();
  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(HAIER_AC, irsend.capture.decode_type);
  EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);

  IRHaierAC haier(0);
  haier.setRaw(irsend.capture.state);
  EXPECT_EQ("Command: 12 (Health), Mode: 0 (AUTO), Temp: 30C, Fan: 0 (AUTO), "
            "Swing: 0 (Off), Sleep: Off, Health: On, "
            "Current Time: 00:09, On Timer: Off, Off Timer: Off",
            haier.toString());
}
// Decode a problematic Panasonic AC message
TEST(TestDecodePanasonicAC, Issue540) {
  IRsendTest irsend(0);
  IRrecv irrecv(0);
  irsend.begin();

  // Data from Issue #540
  uint16_t rawData[439] = {
      3512, 1714, 466, 408,  466, 1280, 470, 408,  466, 412,  466, 408,
      466,  412,  462, 412,  466, 414,  466, 408,  466, 412,  462, 412,
      466,  412,  466, 408,  466, 1280, 466, 412,  462, 416,  462, 412,
      466,  408,  466, 412,  462, 416,  462, 412,  462, 1282, 462, 1284,
      462,  1288, 466, 412,  462, 412,  462, 1284, 462, 416,  440, 438,
      462,  412,  462, 412,  462, 416,  466, 412,  462, 412,  462, 412,
      440,  442,  462, 412,  462, 412,  460, 418,  462, 416,  462, 412,
      462,  418,  462, 412,  462, 416,  462, 412,  436, 442,  462, 412,
      460,  418,  462, 416,  462, 412,  460, 412,  462, 420,  436, 438,
      462,  412,  462, 416,  432, 448,  436, 438,  436, 1310, 436, 1310,
      462,  420,  432, 442,  436, 438,  462, 416,  432, 444,  432, 10008,
      3480, 1744, 492, 382,  492, 1254, 492, 386,  488, 390,  492, 382,
      492,  386,  488, 386,  492, 386,  492, 386,  488, 386,  488, 386,
      492,  386,  492, 382,  492, 1258, 488, 386,  488, 390,  492, 386,
      488,  386,  488, 386,  492, 390,  488, 386,  488, 1256, 488, 1258,
      488,  1262, 488, 390,  488, 386,  488, 1258, 488, 390,  488, 392,
      488,  386,  488, 386,  488, 394,  488, 386,  488, 386,  488, 390,
      488,  390,  488, 386,  488, 390,  462, 412,  488, 390,  462, 1282,
      488,  390,  456, 416,  458, 1292, 456, 1288, 488, 1258, 488, 392,
      456,  422,  488, 390,  484, 392,  484, 1262, 458, 420,  484, 1262,
      482,  1262, 488, 392,  484, 394,  484, 416,  436, 442,  458, 416,
      458,  422,  430, 448,  432, 442,  458, 416,  458, 1296, 432, 1314,
      458,  1288, 432, 1312, 432, 1322, 428, 446,  428, 1318, 432, 442,
      432,  1318, 432, 1318, 428, 446,  428, 1318, 428, 1322, 430, 448,
      426,  448,  428, 452,  426, 452,  426, 448,  428, 472,  400, 478,
      402,  478,  402, 472,  402, 476,  402, 472,  402, 478,  402, 472,
      402,  1348, 398, 1348, 398, 1352, 398, 508,  370, 478,  398, 476,
      398,  512,  366, 508,  370, 502,  372, 508,  340, 538,  372, 504,
      344,  1400, 344, 1400, 346, 1434, 314, 560,  316, 588,  290, 560,
      314,  564,  396, 400,  474, 400,  480, 394,  480, 404,  474, 400,
      454,  446,  454, 426,  448, 430,  424, 450,  428, 452,  448, 426,
      426,  452,  424, 1322, 454, 426,  450, 424,  426, 452,  428, 452,
      450,  424,  428, 446,  426, 1322, 454, 426,  422, 450,  454, 426,
      448,  430,  454, 426,  448, 426,  428, 446,  454, 430,  454, 422,
      452,  424,  424, 452,  452, 430,  424, 452,  452, 426,  448, 426,
      426,  456,  448, 426,  448, 1296, 424, 1322, 426, 1326, 450, 1270,
      478,  422,  454, 424,  424, 450,  454};
  uint8_t expectedState[kPanasonicAcStateLength] = {
      0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
      0x20, 0xE0, 0x04, 0x00, 0x39, 0x34, 0x80, 0xAF, 0x0D,
      0x00, 0x0E, 0xE0, 0x00, 0x00, 0x81, 0x00, 0x00, 0x1E};

  irsend.sendRaw(rawData, 439, kPanasonicFreq);
  irsend.makeDecodeResult();

  ASSERT_TRUE(irrecv.decode(&irsend.capture));
  ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type);
  EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
  EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
  EXPECT_FALSE(irsend.capture.repeat);
  IRPanasonicAc pana(0);
  pana.setRaw(irsend.capture.state);
  // TODO(crankyoldgit): Try to figure out what model this should be.
  EXPECT_EQ(
      "Model: 0 (UNKNOWN), Power: On, Mode: 3 (COOL), Temp: 26C, "
      "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), "
      "Swing (Horizontal): 13 (AUTO), Quiet: Off, Powerful: Off, "
      "Clock: 0:00, On Timer: Off, Off Timer: Off",
      pana.toString());
}
TEST(TestHaierACClass, MessageConstuction) {
  IRHaierAC haier(0);

  EXPECT_EQ("Command: 1 (On), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), "
            "Swing: 0 (Off), Sleep: Off, Health: Off, "
            "Current Time: 00:00, On Timer: Off, Off Timer: Off",
            haier.toString());
  haier.setMode(HAIER_AC_COOL);
  haier.setTemp(21);
  haier.setFan(HAIER_AC_FAN_HIGH);
  EXPECT_EQ("Command: 3 (Fan), Mode: 1 (COOL), Temp: 21C, Fan: 3 (MAX), "
            "Swing: 0 (Off), Sleep: Off, Health: Off, "
            "Current Time: 00:00, On Timer: Off, Off Timer: Off",
            haier.toString());
  haier.setSwing(HAIER_AC_SWING_CHG);
  haier.setHealth(true);
  haier.setSleep(true);
  haier.setCurrTime(615);  // 10:15am
  EXPECT_EQ("Command: 8 (Sleep), Mode: 3 (HEAT), Temp: 21C, Fan: 3 (MAX), "
            "Swing: 3 (Chg), Sleep: On, Health: On, "
            "Current Time: 10:15, On Timer: Off, Off Timer: Off",
            haier.toString());
  haier.setOnTimer(800);  // 1:20pm
  haier.setOffTimer(1125);  // 6:45pm
  haier.setCommand(HAIER_AC_CMD_ON);

  EXPECT_EQ("Command: 1 (On), Mode: 2 (DRY), Temp: 21C, Fan: 2, "
            "Swing: 3 (Chg), Sleep: On, Health: On, "
            "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45",
            haier.toString());

  // Now change a few already set things.
  haier.setMode(HAIER_AC_HEAT);
  EXPECT_EQ("Command: 2 (Mode), Mode: 3 (HEAT), Temp: 21C, Fan: 2, "
            "Swing: 3 (Chg), Sleep: On, Health: On, "
            "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45",
            haier.toString());

  haier.setTemp(25);
  EXPECT_EQ("Command: 6 (Temp Up), Mode: 3 (HEAT), Temp: 25C, Fan: 2, "
            "Swing: 3 (Chg), Sleep: On, Health: On, "
            "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45",
            haier.toString());

  uint8_t expectedState[HAIER_AC_STATE_LENGTH] = {
    0xA5, 0x96, 0xEA, 0xCF, 0x32, 0x2D, 0x0D, 0x74, 0xD4};
  EXPECT_STATE_EQ(expectedState, haier.getRaw(), HAIER_AC_BITS);

  // Check that the checksum is valid.
  EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw()));

  // Now load up some random data.
  uint8_t randomState[HAIER_AC_STATE_LENGTH] = {
      0x52, 0x49, 0x50, 0x20, 0x54, 0x61, 0x6C, 0x69, 0x61};
  EXPECT_FALSE(IRHaierAC::validChecksum(randomState));
  haier.setRaw(randomState);
  EXPECT_EQ("Command: 9 (Timer Set), Mode: 3 (HEAT), Temp: 20C, Fan: 2, "
            "Swing: 1 (Up), Sleep: On, Health: Off, "
            "Current Time: 16:32, On Timer: Off, Off Timer: Off",
            haier.toString());
  // getRaw() should correct the checksum.
  EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw()));
}