Skip to content

Commit 4e64aa9

Browse files
committed
Add task 11.06
1 parent 50e9893 commit 4e64aa9

File tree

10 files changed

+253
-1
lines changed

10 files changed

+253
-1
lines changed

week-12/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
set(DIRS task-11-01 task-11-03)
1+
set(DIRS task-11-01 task-11-03 task-11-06)
22
foreach(DIR ${DIRS})
33
add_subdirectory(${DIR})
44
endforeach()

week-12/task-11-06/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
include_directories(include)
2+
3+
add_subdirectory(test)

week-12/task-11-06/include/circle.hpp

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <numbers>
4+
#include "ivisitor.hpp"
5+
#include "shape.hpp"
6+
7+
namespace geometry2d {
8+
9+
class Circle : public Shape {
10+
public:
11+
static constexpr double pi = std::numbers::pi;
12+
13+
explicit Circle(double r) : radius_(r) {
14+
if (radius_ <= 0) {
15+
throw std::invalid_argument("Radius must be positive.");
16+
}
17+
}
18+
19+
double radius() const { return radius_; }
20+
21+
double perimeter() const override {
22+
return 2 * pi * radius_;
23+
}
24+
double area() const override {
25+
return pi * radius_ * radius_;
26+
}
27+
28+
void visit_by(const IVisitor& visitor) const override {
29+
visitor.visit(*this);
30+
}
31+
32+
private:
33+
double radius_;
34+
};
35+
36+
} // namespace geometry2d
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
namespace geometry2d {
4+
5+
class Circle;
6+
class Square;
7+
class Triangle;
8+
class Shape;
9+
10+
class IVisitor {
11+
public:
12+
virtual ~IVisitor() = default;
13+
14+
virtual void visit(const Circle& c) const = 0;
15+
virtual void visit(const Square& s) const = 0;
16+
virtual void visit(const Triangle& t) const = 0;
17+
};
18+
19+
} // namespace geometry2d
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <iostream>
4+
5+
#include "ivisitor.hpp"
6+
#include "circle.hpp"
7+
#include "square.hpp"
8+
#include "triangle.hpp"
9+
10+
namespace geometry2d {
11+
12+
class Serializer : public IVisitor {
13+
public:
14+
void visit(const Circle &c) const override {
15+
std::cout << "Circle:" << std::endl;
16+
std::cout << "\tradius: " << c.radius() << std::endl;
17+
std::cout << "\t\tperimeter: " << c.perimeter() << std::endl;
18+
std::cout << "\t\tarea: " << c.area() << std::endl;
19+
}
20+
void visit(const Square &s) const override {
21+
std::cout << "Square:" << std::endl;
22+
std::cout << "\tside: " << s.side() << std::endl;
23+
std::cout << "\t\tperimeter: " << s.perimeter() << std::endl;
24+
std::cout << "\t\tarea: " << s.area() << std::endl;
25+
}
26+
void visit(const Triangle &t) const override {
27+
std::cout << "Triangle:" << std::endl;
28+
std::cout << "\tside1: " << t.side1() << std::endl;
29+
std::cout << "\tside2: " << t.side2() << std::endl;
30+
std::cout << "\tside3: " << t.side3() << std::endl;
31+
std::cout << "\t\tperimeter: " << t.perimeter() << std::endl;
32+
std::cout << "\t\tarea: " << t.area() << std::endl;
33+
}
34+
};
35+
36+
} // namespace geometry2d

week-12/task-11-06/include/shape.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
namespace geometry2d {
4+
5+
#include "ivisitor.hpp"
6+
7+
class Shape {
8+
public:
9+
virtual ~Shape() = default;
10+
11+
virtual void visit_by(const IVisitor& visitor) const = 0;
12+
virtual double perimeter() const = 0;
13+
virtual double area() const = 0;
14+
};
15+
16+
} // namespace geometry2d

week-12/task-11-06/include/square.hpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include "ivisitor.hpp"
4+
#include "shape.hpp"
5+
6+
namespace geometry2d {
7+
8+
class Square : public Shape {
9+
public:
10+
explicit Square(double s) : side_(s) {
11+
if (side_ <= 0) {
12+
throw std::invalid_argument("Side must be positive.");
13+
}
14+
}
15+
16+
double side() const { return side_; }
17+
18+
double perimeter() const override {
19+
return 4 * side_;
20+
}
21+
double area() const override {
22+
return side_ * side_;
23+
}
24+
25+
void visit_by(const IVisitor& visitor) const override {
26+
visitor.visit(*this);
27+
}
28+
29+
private:
30+
double side_;
31+
};
32+
33+
} // namespace geometry2d
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#include <cmath>
4+
5+
#include "shape.hpp"
6+
7+
namespace geometry2d {
8+
9+
class Triangle : public Shape {
10+
public:
11+
Triangle(double s1, double s2, double s3) : side1_(s1), side2_(s2), side3_(s3) {
12+
if (side1_ <= 0 || side2_ <= 0 || side3_ <= 0) {
13+
throw std::invalid_argument("All sides must be positive.");
14+
}
15+
if (side1_ + side2_ <= side3_ || side1_ + side3_ <= side2_ || side2_ + side3_ <= side1_) {
16+
throw std::invalid_argument("Invalid triangle sides.");
17+
}
18+
}
19+
20+
double side1() const { return side1_; }
21+
double side2() const { return side2_; }
22+
double side3() const { return side3_; }
23+
24+
double perimeter() const override {
25+
return side1_ + side2_ + side3_;
26+
}
27+
double area() const override {
28+
const double p = perimeter() / 2;
29+
return std::sqrt(p * (p - side1_) * (p - side2_) * (p - side3_));
30+
}
31+
32+
void visit_by(const IVisitor& visitor) const override {
33+
visitor.visit(*this);
34+
}
35+
36+
private:
37+
double side1_, side2_, side3_;
38+
};
39+
40+
} // namespace geometry2d
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp_test(test-11-06.cpp)
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <iostream>
4+
#include <memory>
5+
#include <sstream>
6+
7+
#include "serializer.hpp"
8+
9+
using geometry2d::Circle;
10+
using geometry2d::Serializer;
11+
using geometry2d::Shape;
12+
using geometry2d::Square;
13+
using geometry2d::Triangle;
14+
15+
std::string capture_output(const std::function<void()>& printer_func) {
16+
const std::ostringstream oss;
17+
auto old_cout_buffer = std::cout.rdbuf(oss.rdbuf());
18+
printer_func();
19+
std::cout.rdbuf(old_cout_buffer);
20+
return oss.str();
21+
}
22+
23+
TEST(Serializer, ShapeCircle) {
24+
const Serializer serializer{};
25+
const std::unique_ptr<Shape> shape = std::make_unique<Circle>(4);
26+
const std::string expected_output =
27+
"Circle:\n"
28+
"\tradius: 4\n"
29+
"\t\tperimeter: 25.1327\n"
30+
"\t\tarea: 50.2655\n";
31+
const std::string output = capture_output([&]() { shape->visit_by(serializer); });
32+
EXPECT_EQ(output, expected_output);
33+
}
34+
35+
TEST(Serializer, ShapeSquare) {
36+
const Serializer serializer{};
37+
const std::unique_ptr<Shape> shape = std::make_unique<Square>(5);
38+
const std::string expected_output =
39+
"Square:\n"
40+
"\tside: 5\n"
41+
"\t\tperimeter: 20\n"
42+
"\t\tarea: 25\n";
43+
const std::string output = capture_output([&]() { shape->visit_by(serializer); });
44+
EXPECT_EQ(output, expected_output);
45+
}
46+
47+
TEST(Serializer, ShapeTriangle) {
48+
const Serializer serializer{};
49+
const std::unique_ptr<Shape> shape = std::make_unique<Triangle>(3, 4, 5);
50+
const std::string expected_output =
51+
"Triangle:\n"
52+
"\tside1: 3\n"
53+
"\tside2: 4\n"
54+
"\tside3: 5\n"
55+
"\t\tperimeter: 12\n"
56+
"\t\tarea: 6\n";
57+
const std::string output = capture_output([&]() { shape->visit_by(serializer); });
58+
EXPECT_EQ(output, expected_output);
59+
}
60+
61+
TEST(Serializer, InvalidCircleRadius) { EXPECT_THROW(Circle(-1), std::invalid_argument); }
62+
63+
TEST(Serializer, InvalidSquareSide) { EXPECT_THROW(Square(0), std::invalid_argument); }
64+
65+
TEST(Serializer, InvalidTriangleSides) {
66+
EXPECT_THROW(Triangle(1, 2, 3), std::invalid_argument);
67+
EXPECT_THROW(Triangle(-1, 2, 2), std::invalid_argument);
68+
}

0 commit comments

Comments
 (0)