user21075: I recently gave the students in my Arduino-based programming class a project to write some simple unit tests and fix the bugs that they encountered as they did.  The class in question mostly stores a bunch of Arduino-style String objects, with various getters and setters and a couple of constructors.
The test code that they're supposed to write involved creating two instances of the class (on the stack) and verifying that the constructors set the values correctly.  When I went through the exercise myself, everything worked.
When the students repeated the exercise, the first object worked.  The second object returned empty strings.  If they commented out the first object, the second object began working.  I couldn't find any obvious mistakes that could explain these failures.
After staring at their code for about ten minutes to make sure I wasn't losing it, I compared Arduino IDE versions to make sure my machine was running the same version.  It was.
Next, I unplugged one of their Arduino Uno devices and plugged in my Mega 2560.  The exact same source code passed the unit tests as expected.  That means the test failures were caused by some subtle difference between the Arduino Uno and the Mega 2560—either in the hardware or in the compiler.
Before I file a bug against the Arduino Uno compiler (v1.6.7, though I don't see anything in the 1.6.8/1.6.9 release notes that imply any compiler changes since then), I wanted to make sure I wasn't missing something subtle.  Could somebody take a look at this and see if I missed anything?
I've included a condensed version of the class in question below (with irrelevant bits removed).  You can see the complete set of exercises at:
https://sites.google.com/a/cabrillo.edu/cs-11m/schedule/unit-testing-exercises
The tests failed unexpectedly after they added the second AddressBookEntry object.
Class Declaration (partial)
class AddressBookEntry {

  public:
    AddressBookEntry(void);
    AddressBookEntry(String title, String firstName,
                     String middleName, String lastName,
                     String suffix);

    String title(void);
    String firstName(void);

...

  private:
    String _title;      // Mr.
    String _firstName;  // Barack
    String _middleName; // Hussein
    String _lastName;   // Obama
    String _suffix;     // Sr.

    String _addressLine1; // The White House
    String _addressLine2; // 1600 Pennsylvania Ave.
    String _city;         // Washington
    String _state;        // DC
    String _zip;          // 20500
    String _plusFour;     // 0001   (from 20500-0001)

    String _homePhone;    // Unknown
    String _mobilePhone;  // Unknown
    String _workPhone;    // 202-456-1414

Implementation (partial)
#define assert(condition) { \
  if (!(condition)) { \
    Serial.print(__FILE__); \
    Serial.print(":"); \
    Serial.print(__LINE__); \
    Serial.println(": Assertion failed: " #condition); \
    while (1); \
  } \
}

bool AddressBookEntry::runTests(void)
{
  Serial.println("Running tests.\n"); Serial.flush();

  AddressBookEntry testEntry("Mr.", "Jim", "Bob", "Murphy", "Sr.");

  Serial.println(testEntry.title());
  Serial.flush();

  assert(testEntry.title() == "Mr.");
  assert(testEntry.firstName() == "Jim");
  assert(testEntry.middleName() == "Bob");
  assert(testEntry.lastName() == "Murphy");
  assert(testEntry.suffix() == "Sr.");
  testEntry.setMiddleName("Phil");
  assert(testEntry.middleName() == "Phil");

  AddressBookEntry obamaEntry("Mr.", "Barack", "Hussein", "Obama", "");


  assert(obamaEntry.title() == "Mr."); // fails
  assert(obamaEntry.firstName() == "Barack"); // fails
  assert(obamaEntry.middleName() == "Hussein"); // stopped checking here.
  assert(obamaEntry.lastName() == "Obama");
  assert(obamaEntry.suffix() == "");

  Serial.println("All tests passed.\n"); Serial.flush();
}

AddressBookEntry::AddressBookEntry()
{
  _title = "";
  _firstName = "";
  _middleName = "";
  _lastName = "";
  _suffix = "";

  _addressLine1 = "";
  _addressLine2 = "";
  _city = "";
  _state = "";
  _zip = -1; // Deliberate bug
  _plusFour = -1; // Deliberate bug

  _homePhone = "";
  _mobilePhone = "";
  _workPhone = "";
}

AddressBookEntry::AddressBookEntry(String title, String firstName,
                                   String middleName, String lastName,
                                   String suffix)
{
  _title = title;
  _firstName = firstName;
  _middleName = middleName;
  _lastName = lastName;
  _suffix = suffix;

  _addressLine1 = "";
  _addressLine2 = "";
  _city = "";
  _state = "";
  _zip = -1; // Deliberate bug
  _plusFour = -1; // Deliberate bug

  _homePhone = "";
  _mobilePhone = "";
  _workPhone = "";

String str = "";
  Serial.println(str + "title is \"" + title + "\"");
}

String AddressBookEntry::title()
{
  return _title;
}

String AddressBookEntry::firstName()
{
  return _firstName;
}

... // remaining getters are similar

Calling Code (from setup() function)
  Serial.begin(9600);
  AddressBookEntry myEntry;
  myEntry.runTests();


user4143: 
That means the test failures were caused by some subtle difference between the Arduino Uno and the Mega 2560—either in the hardware or in the compiler.

Not a subtle difference - a big difference.  The Mega2560 has considerably more RAM than the UNO (8kB compared to 2kB). 
All those strings are using RAM. Lots of RAM.  Your Mega2560 has enough RAM to cope (just), but the UNO just dumps its stack in a heap all over the floor1 at the mere thought of trying to handle that quantity of string data.

1: That's a technical way of describing the stack and the heap meeting and, if there were no protection, colliding into each other.

21075: <p>I recently gave the students in my Arduino-based programming class a project to write some simple unit tests and fix the bugs that they encountered as they did.  The class in question mostly stores a bunch of Arduino-style String objects, with various getters and setters and a couple of constructors.</p>

<p>The test code that they're supposed to write involved creating two instances of the class (on the stack) and verifying that the constructors set the values correctly.  When I went through the exercise myself, everything worked.</p>

<p>When the students repeated the exercise, the first object worked.  The second object returned empty strings.  If they commented out the first object, the second object began working.  I couldn't find any obvious mistakes that could explain these failures.</p>

<p>After staring at their code for about ten minutes to make sure I wasn't losing it, I compared Arduino IDE versions to make sure my machine was running the same version.  It was.</p>

<p>Next, I unplugged one of their Arduino Uno devices and plugged in my Mega 2560.  The exact same source code passed the unit tests as expected.  That means the test failures were caused by some subtle difference between the Arduino Uno and the Mega 2560—either in the hardware or in the compiler.</p>

<p>Before I file a bug against the Arduino Uno compiler (v1.6.7, though I don't see anything in the 1.6.8/1.6.9 release notes that imply any compiler changes since then), I wanted to make sure I wasn't missing something subtle.  Could somebody take a look at this and see if I missed anything?</p>

<p>I've included a condensed version of the class in question below (with irrelevant bits removed).  You can see the complete set of exercises at:</p>

<p><a href="https://sites.google.com/a/cabrillo.edu/cs-11m/schedule/unit-testing-exercises" rel="nofollow">https://sites.google.com/a/cabrillo.edu/cs-11m/schedule/unit-testing-exercises</a></p>

<p>The tests failed unexpectedly after they added the second <code>AddressBookEntry</code> object.</p>

<p><strong>Class Declaration (partial)</strong></p>

<pre><code>class AddressBookEntry {

  public:
    AddressBookEntry(void);
    AddressBookEntry(String title, String firstName,
                     String middleName, String lastName,
                     String suffix);

    String title(void);
    String firstName(void);

...

  private:
    String _title;      // Mr.
    String _firstName;  // Barack
    String _middleName; // Hussein
    String _lastName;   // Obama
    String _suffix;     // Sr.

    String _addressLine1; // The White House
    String _addressLine2; // 1600 Pennsylvania Ave.
    String _city;         // Washington
    String _state;        // DC
    String _zip;          // 20500
    String _plusFour;     // 0001   (from 20500-0001)

    String _homePhone;    // Unknown
    String _mobilePhone;  // Unknown
    String _workPhone;    // 202-456-1414
</code></pre>

<p><strong>Implementation (partial)</strong></p>

<pre><code>#define assert(condition) { \
  if (!(condition)) { \
    Serial.print(__FILE__); \
    Serial.print(":"); \
    Serial.print(__LINE__); \
    Serial.println(": Assertion failed: " #condition); \
    while (1); \
  } \
}

bool AddressBookEntry::runTests(void)
{
  Serial.println("Running tests.\n"); Serial.flush();

  AddressBookEntry testEntry("Mr.", "Jim", "Bob", "Murphy", "Sr.");

  Serial.println(testEntry.title());
  Serial.flush();

  assert(testEntry.title() == "Mr.");
  assert(testEntry.firstName() == "Jim");
  assert(testEntry.middleName() == "Bob");
  assert(testEntry.lastName() == "Murphy");
  assert(testEntry.suffix() == "Sr.");
  testEntry.setMiddleName("Phil");
  assert(testEntry.middleName() == "Phil");

  AddressBookEntry obamaEntry("Mr.", "Barack", "Hussein", "Obama", "");


  assert(obamaEntry.title() == "Mr."); // fails
  assert(obamaEntry.firstName() == "Barack"); // fails
  assert(obamaEntry.middleName() == "Hussein"); // stopped checking here.
  assert(obamaEntry.lastName() == "Obama");
  assert(obamaEntry.suffix() == "");

  Serial.println("All tests passed.\n"); Serial.flush();
}

AddressBookEntry::AddressBookEntry()
{
  _title = "";
  _firstName = "";
  _middleName = "";
  _lastName = "";
  _suffix = "";

  _addressLine1 = "";
  _addressLine2 = "";
  _city = "";
  _state = "";
  _zip = -1; // Deliberate bug
  _plusFour = -1; // Deliberate bug

  _homePhone = "";
  _mobilePhone = "";
  _workPhone = "";
}

AddressBookEntry::AddressBookEntry(String title, String firstName,
                                   String middleName, String lastName,
                                   String suffix)
{
  _title = title;
  _firstName = firstName;
  _middleName = middleName;
  _lastName = lastName;
  _suffix = suffix;

  _addressLine1 = "";
  _addressLine2 = "";
  _city = "";
  _state = "";
  _zip = -1; // Deliberate bug
  _plusFour = -1; // Deliberate bug

  _homePhone = "";
  _mobilePhone = "";
  _workPhone = "";

String str = "";
  Serial.println(str + "title is \"" + title + "\"");
}

String AddressBookEntry::title()
{
  return _title;
}

String AddressBookEntry::firstName()
{
  return _firstName;
}

... // remaining getters are similar
</code></pre>

<p><strong>Calling Code (from setup() function)</strong></p>

<pre><code>  Serial.begin(9600);
  AddressBookEntry myEntry;
  myEntry.runTests();
</code></pre>
 4143: <blockquote>
  <p>That means the test failures were caused by some subtle difference between the Arduino Uno and the Mega 2560—either in the hardware or in the compiler.</p>
</blockquote>

<p>Not a subtle difference - a big difference.  The Mega2560 has considerably more RAM than the UNO (8kB compared to 2kB). </p>

<p>All those strings are using RAM. Lots of RAM.  Your Mega2560 has enough RAM to cope (just), but the UNO just dumps its stack in a heap all over the floor<sup>1</sup> at the mere thought of trying to handle that quantity of string data.</p>

<hr>

<p><sup>1: That's a technical way of describing the stack and the heap meeting and, if there were no protection, colliding into each other.</sup></p>
