void checkFinishedAfter(const openstudio::runmanager::Job &t_before, const openstudio::runmanager::Job &t_after)
{
  EXPECT_TRUE(t_before.lastRun());
  EXPECT_TRUE(t_after.lastRun());

  EXPECT_TRUE(t_before.ranBefore(t_after) || (!t_before.ranBefore(t_after) && !t_after.ranBefore(t_before))); // timer resolution requires us to consider the two jobs having run at the same time as "runbefore"
  EXPECT_FALSE(t_after.ranBefore(t_before));

  EXPECT_FALSE(t_before.outOfDate());
  EXPECT_FALSE(t_after.outOfDate());
}
void DataPointJobItemView::update(analysis::RubyMeasure & rubyMeasure, BCLMeasure & bclMeasure, openstudio::runmanager::JobErrors jobErrors, openstudio::runmanager::Job job)
{
  OS_ASSERT(m_dataPointJobHeaderView);

  m_dataPointJobHeaderView->setName(rubyMeasure.name());
  m_dataPointJobHeaderView->setLastRunTime(job.lastRun());
  m_dataPointJobHeaderView->setStatus(job.status(), job.canceled());

  m_dataPointJobHeaderView->m_na->setText("");
  m_dataPointJobHeaderView->m_warnings->setText("");
  m_dataPointJobHeaderView->m_errors->setText("");

  OS_ASSERT(m_dataPointJobContentView);
  m_dataPointJobContentView->clear();

  std::vector<std::string> initialConditions = jobErrors.initialConditions();
  for (const std::string& initialCondition : initialConditions){
    m_dataPointJobContentView->addInitialConditionMessage(initialCondition);
  }

  std::vector<std::string> finalConditions = jobErrors.finalConditions();
  for (const std::string& finalCondition : finalConditions){
    m_dataPointJobContentView->addFinalConditionMessage(finalCondition);
  }

  std::vector<std::string> errors = jobErrors.errors();
  m_dataPointJobHeaderView->setNumErrors(errors.size());
  for (const std::string& errorMessage : errors){
    m_dataPointJobContentView->addErrorMessage(errorMessage);
  }

  // also display std err if job failed and it exists and is not empty
  if (job.lastRun() && !job.running() && !jobErrors.succeeded()){
    try{
      runmanager::Files files(job.outputFiles());
      openstudio::path stdErrPath = files.getLastByFilename("stderr").fullPath;
      std::string stdErrPathStr = toString(stdErrPath);
      std::ifstream ifs(stdErrPathStr.c_str());
      std::string stdErrorMessage((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
      ifs.close();
      if (!stdErrorMessage.empty()){
        m_dataPointJobContentView->addStdErrorMessage(stdErrorMessage);
      }
    }catch(std::exception&){

    }
  }

  std::vector<std::string> warnings = jobErrors.warnings();
  m_dataPointJobHeaderView->setNumWarnings(warnings.size());
  for (const std::string& warningMessage : warnings){
    m_dataPointJobContentView->addWarningMessage(warningMessage);
  }

  std::vector<std::string> infos = jobErrors.infos();
  for (const std::string& infoMessage : infos){
    m_dataPointJobContentView->addInfoMessage(infoMessage);
  }

  if (jobErrors.result == ruleset::OSResultValue::NA){
    m_dataPointJobHeaderView->setNA(true);
  }else{
    m_dataPointJobHeaderView->setNA(false);
  }
}