1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
     117
     118
     119
     120
     121
     122
     123
#include <exception>
#include <iomanip>
#include <iostream>
#include "array-debug.hpp"

template<typename T>
void test_operation(unsigned int test, std::string description,
      T&& operation) {
   std::cout << "Test " << std::setw(2) << std::right << test << ": ";
   std::cout << std::setw(30) << std::left << std::move(description) << " ";
   try {
      operation();
      std::cout << "ok" << std::endl;
   } catch (std::exception& e) {
      std::cout << "exception: " << e.what() << std::endl;
   } catch (...) {
      std::cout << "unknown exception" << std::endl;
   }
}

struct FailingObject {
   class Exception: public std::exception {
      const char* what() const noexcept override {
	 return "FailingObject exception";
      }
   };
   FailingObject() {
      throw Exception();
   }
   FailingObject(const FailingObject& other) {
      throw Exception();
   }
   FailingObject(int i) {
      if (i < 0) throw Exception();
   }
   FailingObject& operator=(const FailingObject& other) {
      throw Exception();
   }
};

int main() {
   unsigned int test = 0;
   test_operation(++test, "Array()", []() { Array<FailingObject>(); });
   test_operation(++test, "Array(0)", []() { Array<FailingObject>(0); });
   test_operation(++test, "Array(1)", []() { Array<FailingObject>(1); });
   test_operation(++test, "Array(1, FailingObject(1))",
      []() { Array<FailingObject>(1, FailingObject(1)); });
   test_operation(++test, "Array(it1, it2) from {1, 2}", []() {
      int values[] = {1, 2, 3};
      Array<FailingObject>(values, values + sizeof(values)/sizeof(values[0]));
   });
   test_operation(++test, "Array(it1, it2) from {1, -2}", []() {
      int values[] = {1, -2};
      Array<FailingObject>(values, values + sizeof(values)/sizeof(values[0]));
   });
   test_operation(++test, "Array{1, 2}", []() {
      Array<FailingObject>{1, 2};
   });
   test_operation(++test, "Array{1, -2}", []() {
      Array<FailingObject>{1, -2};
   });
   test_operation(++test, "Array copy constructor", []() {
      int values[] = {1, 2};
      Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      Array<FailingObject> array2(array);
   });
   test_operation(++test, "Array move constructor", []() {
      int values[] = {1, 2};
      Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      Array<FailingObject>(std::move(array));
   });
   test_operation(++test, "Array swap", []() {
      int values[] = {1, 2};
      Array<FailingObject> array1(values,
	 values + sizeof(values)/sizeof(values[0]));
      Array<FailingObject> array2(values,
	 values + sizeof(values)/sizeof(values[0]));
      using std::swap;
      swap(array1, array2);
   });
   test_operation(++test, "Array assignment", []() {
      int values[] = {1, 2};
      Array<FailingObject> array1(values,
	 values + sizeof(values)/sizeof(values[0]));
      Array<FailingObject> array2;
      array2 = std::move(array1);
   });
   test_operation(++test, "Array get_size", []() {
      int values[] = {1, 2};
      Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      array.get_size();
   });
   test_operation(++test, "Array access by index", []() {
      int values[] = {1, 2};
      Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      array(1);
   });
   test_operation(++test, "Array access by index const", []() {
      int values[] = {1, 2};
      const Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      array(1);
   });
   test_operation(++test, "Array iterators", []() {
      int values[] = {1, 2};
      Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      for (auto& object: array) {
      }
   });
   test_operation(++test, "Array const iterators", []() {
      int values[] = {1, 2};
      const Array<FailingObject> array(values,
	 values + sizeof(values)/sizeof(values[0]));
      for (auto& object: array) {
      }
   });
   std::cout << test << " tests survived." << std::endl;
}