M
M
may_19972016-09-21 17:48:31
C++ / C#
may_1997, 2016-09-21 17:48:31

How is the function (main) implemented, which will perform the check?

class String 
{
private: 
  int len;	
  char *str; 	
public:
  // конструктор по умолчанию 
  String () 
  {
    str = new char[1];
    *str = 0; // код пуст симв
    len = 0;
    std::cout << "k po ymolch \n";
  }
  // конструктор с параметром
  String (char *a) 
  { 
    std::cout<<"param \n";
    int j = 0;
    while (a[j] != 0)
      j++;
    str = new char[j + 1];
    for (int i = 0; i <= j; i++)
      str[i] = a[i];
    

  }
  // копирующий конструктор
  String(const String & b)
  {	
    len = b.len;
    str = new char[len + 1];
    for (int i = 0; i <= len; i++)
      str[i] = b.str[i];
                std::cout<<"kopy  \n";

  }
  
  ~String ()  // деструктор
  {
    delete[] str;
    std::cout<<"delete \n";
  }

  // оператор присваивания
  String & operator =(const String &b)
  {	
    std::cout<<"prisv \n";
    delete[] str;
    len = b.len;
    str = new char[len + 1];
    for (int i = 0; i <= len; i++)
      str[i] = b.str[i];
  }
  String operator +(const String &b) const
  {
    String c;
    c.len = b.len + len;
    c.str = new char[c.len + 1];
    for (int i = 0; i < len; i++)
      str[i] = str[i];
    for (int i = len; i <= c.len; i++)
      str[i] = b.str[i - len];
    std::cout<<"concat + \n";
  }

  String & operator +=(const String &b) 
  {
    *this = *this + b;
    return (*this);
    std::cout<<"concat += \n";
  }
  

  operator const char*() const
  {	
    std::cout<<"priv \n";
    return (str);
  }
  
  char & operator [](const int i)
  {	
    std::cout<<"[] \n";
    return(str[i]);
  }
  char operator [](const int i) const
  {
    std::cout<<"[] const \n";
    return(str[i]);
  }
};

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Mercury13, 2016-09-21
@may_1997

We write a unit test in-house, without a framework. This means that we need to somehow simulate the work of the framework, but on our own and with a minimum of lines.
For convenience, we need one function - and a little preprocessor magic.

#include <iostream>
#include <cstring>

void doAssert(bool condition, int line)
{
    if (condition) {
        std::cout << "Line " << line << " ok" << std::endl;
    } else {
        std::cout << "Line " << line << " FAILED" << std::endl;
    }
}

#define ASSERT(x) doAssert(x, __LINE__)
#define ASSERT_STREQ(x, y) doAssert((std::strcmp(x, y) == 0), __LINE__)

Now let's test something. For example, creating a string. For simplicity, I will check not your string, but std::string.
void testStringCreation()
{
    std::string s;
    ASSERT(s.length() == 0);
    ASSERT(s.empty());
    ASSERT_STREQ("", s.c_str());
}

Let's check the += operation.
void testPlusEq()
{
    std::string s1 = "Alpha";
    std::string s2 = "Bravo";
    s1 += s2;
    ASSERT_STREQ("AlphaBravo", s1.c_str());
}

int main()
{
    testStringCreation();
    testPlusEq();
    return 0;
}

More tests are needed - create a new function and call it from main.
If some test fails, we destroy all calls from main, except for the failed one, and start debugging.
And now a little about what unit tests should be.
1. Isolated. If you destroy some of the tests or run them in a different order, nothing should change - provided, of course, that no one accesses someone else's memory.
2. Each unit test tests one concept, which is indicated in its name. For example: a string is created, the += operation works, etc. There will be a lot of code duplication, just deal with it.
3. But there is nothing wrong with a test relying on concepts tested in other tests. If we test += we assume the copy constructor works and don't test it.
4. Unit tests sometimes have to deal with the internal behavior of an object. In this case, the object must give out some information - for example, the corresponding functions are usually private, but by some preprocessor command they become public.
5. Unit tests usually deal with the simplest behavior of an object. These are not load tests, you just have to put up with it.
6. The principle of the test is as follows. Create initial objects, verify that their INTERNAL (unspecified, implementation dependent) state is correct, perform some action, verify that the action was performed correctly. For example, let's say a string allocates memory with a margin, and we need to check how it expands - then when assigning "Alpha" we make sure that less than 10 characters are allocated, then spend s1 += "Bravo", then we make sure that, for example, 16 characters are allocated.
7. But it is not necessary to check in advance whether the OUTER (specified) state is correct. If we write s1 = "Alpha", then the string is equal to "Alpha", and period. All cases possible in the string = char* operation are, of course, covered by other tests.
8. If suddenly an error is found in the “combat” code, you need to make a unit test that repeats it, then fix the error and state that the test passes and the rest of the tests have not “fallen”.
9. The same if the error happened while testing another concept. We check +=, and a bug in the copy constructor - start a new test that covers this error.
10. In equality tests, the order ASSERT_EQ (what_should_be, what_really_is) is accepted.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question