TEST(ConstantPropagationTest1, constantpropagation) {
  g_redex = new RedexContext();

	const char* dexfile =
    "gen/native/redex/test/integ/constant-propagation-test-dex/constant-propagation.dex";
  if (access(dexfile, R_OK) != 0) {
    dexfile = std::getenv("dexfile");
    ASSERT_NE(nullptr, dexfile);
  }

  std::vector<DexClasses> dexen;
  dexen.emplace_back(load_classes_from_dex(dexfile));
  DexClasses& classes = dexen.back();
  std::cout << "Loaded classes: " << classes.size() << std::endl;

	TRACE(CONSTP, 2, "Code before:\n");
  for(const auto& cls : classes) {
    TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
    if (filter_test_classes(cls->get_name()) < 2) {
      TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
      for (const auto& dm : cls->get_dmethods()) {
        TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
        if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0 ||
            strcmp(dm->get_name()->c_str(), "propagation_2") == 0 ||
            strcmp(dm->get_name()->c_str(), "propagation_3") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
        }
      }
    }
  }

  std::vector<Pass*> passes = {
    new ConstantPropagationPass(),
    new LocalDcePass()
  };

  std::vector<KeepRule> null_rules;
  PassManager manager(passes, null_rules);

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  dummy_cfg.using_seeds = true;
  manager.run_passes(dexen, dummy_cfg);

  TRACE(CONSTP, 2, "Code after:\n");
  for(const auto& cls : classes) {
    TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
    //ASSERT_NE(filter_test_classes(cls->get_name()), REMOVEDCLASS);
    if (filter_test_classes(cls->get_name()) == MAINCLASS) {
      for (const auto& dm : cls->get_dmethods()) {
        TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
        if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            ASSERT_NE(instruction->opcode(), OPCODE_NEW_INSTANCE);
          }
        } else if (strcmp(dm->get_name()->c_str(), "propagation_2") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            ASSERT_NE(instruction->opcode(), OPCODE_INVOKE_STATIC);
          }
        } else if(strcmp(dm->get_name()->c_str(), "propagation_3") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            //ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            //ASSERT_NE(instruction->opcode(), OPCODE_INVOKE_STATIC);
          }
        }
      }
    }
  }
}
TEST(ConstantPropagationTest1, constantpropagation) {
  g_redex = new RedexContext();

	const char* dexfile =
    "gen/native/redex/test/integ/constant-propagation-test-dex/constant-propagation.dex";
  if (access(dexfile, R_OK) != 0) {
    dexfile = std::getenv("dexfile");
    ASSERT_NE(nullptr, dexfile);
  }

  std::vector<DexClasses> dexen;
  dexen.emplace_back(load_classes_from_dex(dexfile));
  DexClasses& classes = dexen.back();
  std::cout << "Loaded classes: " << classes.size() << std::endl;

	TRACE(CONSTP, 2, "Code before:\n");
  for(const auto& cls : classes) {
    if (filter_test_classes(cls->get_name()) < 2) {
  	  TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
  		for (const auto& dm : cls->get_dmethods()) {
  		  TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
  			if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0 ||
            strcmp(dm->get_name()->c_str(), "propagation_2") == 0) {
  			  TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
  			}
  		}
    }
	}

  std::vector<Pass*> passes = {
    new DelInitPass(),
    new RemoveEmptyClassesPass(),
    new ConstantPropagationPass(),
    new LocalDcePass(),
  };

  std::vector<KeepRule> null_rules;
  PassManager manager(passes, null_rules);

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(dexen, dummy_cfg);

	TRACE(CONSTP, 2, "Code after:\n");
	for(const auto& cls : classes) {
    if (filter_test_classes(cls->get_name()) == REMOVEDCLASS) {
      TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
      // To be reverted: These classes should be removed by future optimization.
      ASSERT_TRUE(true);
    } else if (filter_test_classes(cls->get_name()) == MAINCLASS) {
      TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
      for (const auto& dm : cls->get_dmethods()) {
  		  TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
  			if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0) {
  			  TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
  			  for (auto const instruction : dm->get_code()->get_instructions()) {
            // The logic will be reverted when the future
            // development of constant propagation optimization is done, i.e.,
            // The code will be changed to ASSERT_TRUE(false)
            // if IF_EQZ or New Class Instance instruction is found
            if (instruction->opcode() == OPCODE_IF_EQZ ||
                instruction->opcode() == OPCODE_NEW_INSTANCE) {
                    ASSERT_TRUE(true);
            }
  			  }
  			} else if (strcmp(dm->get_name()->c_str(), "propagation_2") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
  			  for (auto const instruction : dm->get_code()->get_instructions()) {
            // The logic will be reverted when the future
            // development of constant propagation optimization is done, i.e.,
            // The code will be changed to ASSERT_TRUE(false)
            // if IF_EQZ or Invote_Static instruction is found
            if (instruction->opcode() == OPCODE_IF_EQZ ||
                instruction->opcode() == OPCODE_INVOKE_STATIC) {
                    ASSERT_TRUE(true);
            }
  			  }
        } else if(strcmp(dm->get_name()->c_str(), "propagation_3") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
  			  for (auto const instruction : dm->get_code()->get_instructions()) {
            // The logic will be reverted when the future
            // development of constant propagation optimization is done, i.e.,
            // The code will be changed to ASSERT_TRUE(false)
            // if IF_EQZ or Invote_Static instruction is found
            if (instruction->opcode() == OPCODE_IF_EQZ ||
                instruction->opcode() == OPCODE_INVOKE_STATIC) {
                    ASSERT_TRUE(true);
            }
  			  }
        }
  		}
    }
	}
}