Grade-school exercise, passes on local host, fails on exercism

I’m getting very strange behavior out of a run of the grade-school tests. I can get 8 tests (all) to pass on my home workstation, but when I submit to exercism I get this error:

We received the following error when we ran your code:

make[2]: *** [CMakeFiles/test_grade-school.dir/build.make:70: CMakeFiles/test_grade-school] Error 1
make[1]: *** [CMakeFiles/Makefile2:111: CMakeFiles/test_grade-school.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

Also if I uncomment the sixth test, the fifth test decides to fail. The sixth test passes if I comment out the fifth. They all pass if I push the “#if defined(EXERCISM_RUN_ALL_TESTS)” to the bottom

I compared my code to a couple other samples and it’s comparable.
Did i find a bug in catch2?

Thanks,
Matthew

make[2]: *** [CMakeFiles/test_grade-school.dir/build.make:70: CMakeFiles/test_grade-school] Error 1
make[1]: *** [CMakeFiles/Makefile2:111: CMakeFiles/test_grade-school.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

This unhelpful error message is often caused by an exception where the tests do not expect one. Without seeing your code I can only guess that it calls .at() with a key that does not exist in the std::map.

Also if I uncomment the sixth test, the fifth test decides to fail. The sixth test passes if I comment out the fifth. They all pass if I push the “#if defined(EXERCISM_RUN_ALL_TESTS)” to the bottom

That sounds either like undefined behavior or state that persists multiple tests.

Please post your solution (in a fenced code blocks) so that the error can be reproduced.

Thanks siebenschaefer.

grade_school.h

#pragma once

// #include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;
namespace grade_school {

  class school {

  public:

    const map<int, vector<string>> roster() const; 
    void add(string, int);
    const vector<string> grade(int) const;
    
  private:

   
    map<int, vector<string>> rost;
    

  }; // class school

}  // namespace grade_school

grade_school.cpp

#include "grade_school.h"

namespace grade_school {

  const map<int, vector<string>> school::roster() const

  {
    return rost;
  }

  void school::add(string name, int grade)
  {
    if(rost.find(grade) == rost.end() || rost[grade].back() < name  )
      {
        rost[grade].push_back(name);
      }
    else
      {
        for(auto i = rost[grade].begin(); i < rost[grade].end(); i++)
          {
            if( name < *i )
              { rost[grade].insert(i, name); }
          }
      }
  } //add

  const vector<string> school::grade(int g) const
  {
    // if(rost.find(g) == rost.end())
    //   {
    //     //vector<string> empty {""};
    //     return vector<string>();
    //   }

    return rost.find(g)->second;
  }
  
}  // namespace grade_school

school::grade(int g) can start with

    if(rost.find(g) == rost.end())
    {
        return vector<string>();
    }

I agree, that should work. If I use:

  return rost.at(g);

to finish the method, I get a seg violation

That is… if i don’t comment out the previous test:

// TEST_CASE("grade_returns_the_students_in_that_grade_in_alphabetical_order") {
//     grade_school::school school_;
//     school_.add("Franklin", 5);
//     school_.add("Bradley", 5);
//     school_.add("Jeff", 1);

//     const auto actual = school_.grade(5);

//     const vector<string> expected{"Bradley", "Franklin"};
//     REQUIRE(expected == actual);
// }

and then it works fine.

This is the failing test (right after the above test):

TEST_CASE("grade_returns_an_empty_array_if_there_are_no_students_in_that_grade") {
    const grade_school::school school_{};
    const auto actual = school_.grade(1);

    REQUIRE(actual.empty());
}

To make things even more interesting, if I reverse the test commenting so the first test (grade_returns…alpahbetical_order) is uncommented and the second is commented (grade_returns_an_empty_array…), then I get 5 out of 5 passing again.

Also if I activate all tests, I get 8 for 8, but on my laptop, not on the exercism host.

After the insert() in school::add() we should return or break. Try a web search for “Iterator invalidation”

1 Like

keiraville, that was a very good catch! Of course I should break and return. I added both. Tests have returned to working normally. The exercise now passes when submitted.

Thank you!!

2 Likes