TriangleClassifier¶
Créez le répertoire
TP9/avec la structure suivante :
TP9/
├── include/
│ └── triangle-classifier.h
├── source/
│ ├── triangle-classifier.cpp
│ └── main.cpp
├── tests/
│ ├── include/
│ │ └── triangle-classifier-test.h
│ └── source/
│ ├── triangle-classifier-test.cpp
│ └── main.cpp
└── makefileRecopiez les codes suivants pour les différents fichiers.
EXECUTABLE = triangle-classifier
TEST_EXECUTABLE = triangle-classifier-tests
CXX = g++
CXXFLAGS = -std=c++17 -Iinclude
TEST_CXXFLAGS = -std=c++17 -Iinclude -Itests/include
SOURCES = $(wildcard source/*.cpp)
TEST_SOURCES = $(wildcard tests/source/*.cpp)
OBJECTS = $(patsubst source/%.cpp,build/objects/%.o,$(SOURCES))
TEST_OBJECTS = $(patsubst tests/source/%.cpp,build/tests/objects/%.o,$(TEST_SOURCES))
DEPENDENCIES = $(patsubst source/%.cpp,build/dependencies/%.d,$(SOURCES))
TEST_DEPENDENCIES = $(patsubst tests/source/%.cpp,build/tests/dependencies/%.d,$(TEST_SOURCES))
SRC_OBJECTS_NO_MAIN = $(filter-out build/objects/main.o,$(OBJECTS))
all: build/binaries/$(EXECUTABLE)
build:
mkdir -p build/objects build/dependencies build/binaries build/tests/objects build/tests/dependencies build/tests/binaries
build/binaries/$(EXECUTABLE): $(OBJECTS) | build
$(CXX) $(OBJECTS) -o build/binaries/$(EXECUTABLE)
build/tests/binaries/$(TEST_EXECUTABLE): $(SRC_OBJECTS_NO_MAIN) $(TEST_OBJECTS) | build
$(CXX) $(SRC_OBJECTS_NO_MAIN) $(TEST_OBJECTS) -o build/tests/binaries/$(TEST_EXECUTABLE)
build/objects/%.o: source/%.cpp | build
$(CXX) $(CXXFLAGS) -MMD -MF build/dependencies/$*.d -c $< -o $@
build/tests/objects/%.o: tests/source/%.cpp | build
$(CXX) $(TEST_CXXFLAGS) -MMD -MF build/tests/dependencies/$*.d -c $< -o $@
clean:
rm -rf build
run:
./build/binaries/$(EXECUTABLE)
tests: build/tests/binaries/$(TEST_EXECUTABLE)
./build/tests/binaries/$(TEST_EXECUTABLE)
.PHONY: all build clean run tests
-include $(DEPENDENCIES)
-include $(TEST_DEPENDENCIES)#include "triangle-classifier.h"
#include <string>
std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
std::string result = "";
return result;
}#ifndef TRIANGLE_CLASSIFIER_H
#define TRIANGLE_CLASSIFIER_H
#include <string>
/**
* Contains only the classifyTriangle method.
*
* classifyTriangle is a method that takes the lengths of three sides
* and returns a string describing the type of triangle formed by these sides.
*/
class TriangleClassifier {
public:
/**
* Returns a string describing the triangle.
*
* classifyTriangle returns the string according to the following rules:
* 1. if at least one side is less than or equal to 0, then the triangle is "invalid";
* 2. if the sum of any two sides is less than or equal to the third side, then the triangle is "invalid";
* 3. if all three sides are equal, then the triangle is "equilateral";
* 4. if exactly two sides are equal, then the triangle is "isosceles";
* 5. if all three sides are different, then the triangle is "scalene";
* 6. always apply the rules in order, from rule 1 to rule 5.
*
* @param firstSide Length of the first side.
* @param secondSide Length of the second side.
* @param thirdSide Length of the third side.
* @return The type of triangle according to the rules above.
*/
static std::string classifyTriangle(int firstSide, int secondSide, int thirdSide);
};
/**
* @example
* \code{.cpp}
* std::cout << TriangleClassifier::classifyTriangle(3, 3, 3); \\ Output: "equilateral"
* std::cout << TriangleClassifier::classifyTriangle(5, 5, 3); \\ Output: "isosceles"
* std::cout << TriangleClassifier::classifyTriangle(4, 5, 6); \\ Output: "scalene"
* std::cout << TriangleClassifier::classifyTriangle(1, 1, 3); \\ Output: "invalid"
* \endcode
*/
#endif#include "triangle-classifier.h"
#include <iostream>
int main() {
int firstSide;
int secondSide;
int thirdSide;
std::cout << "Enter the first side: ";
std::cin >> firstSide;
std::cout << "Enter the second side: ";
std::cin >> secondSide;
std::cout << "Enter the third side: ";
std::cin >> thirdSide;
std::string result = TriangleClassifier::classifyTriangle(firstSide, secondSide, thirdSide);
std::cout << "Triangle type: " << result << std::endl;
return 0;
}#include "triangle-classifier.h"
#include "triangle-classifier-test.h"
#include <iostream>
#include <cassert>
void TriangleClassifierTest::runTests() {
std::cout << "All tests passed\n";
}#ifndef TRIANGLE_CLASSIFIER_TEST_H
#define TRIANGLE_CLASSIFIER_TEST_H
class TriangleClassifierTest
{
public:
static void runTests();
};
#endif#include "triangle-classifier-test.h"
int main() {
TriangleClassifierTest::runTests();
return 0;
}Rappel : makefile
makepour compiler le code source.make runpour exécuter le programme principal et tester le code via des entrées dans le terminal.make testspour compiler et exécuter les tests.Vous pouvez ajouter l’option
-sàmakepour obtenir une sortie moins verbeuse (par exemplemake -s testsoumake -s run).
Lisez la documentation de la classe
TriangleClassifier.Implémentez les tests de la fonction
classifyTriangledanstriangle-classifier-test.cpp.Si vous avez bien écrit vos tests, les implémentations fautives suivantes de
classifyTrianglene devraient pas passer tous les tests :
std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
if (firstSide == secondSide) {
return "isosceles";
}
if (firstSide == secondSide && secondSide == thirdSide) {
return "equilateral";
}
return "scalene";
}std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
if (firstSide <= 0 || secondSide <= 0 || thirdSide <= 0) {
return "invalid";
}
if (firstSide + secondSide <= thirdSide) {
return "invalid";
}
if (firstSide == secondSide) {
return "isosceles";
}
if (firstSide == secondSide && secondSide == thirdSide) {
return "equilateral";
}
return "scalene";
}std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
if (firstSide <= 0 || secondSide <= 0 || thirdSide <= 0) {
return "invalid";
}
if (firstSide + secondSide <= thirdSide || firstSide + thirdSide <= secondSide || secondSide + thirdSide <= firstSide) {
return "invalid";
}
if (firstSide == secondSide) {
return "isosceles";
}
if (firstSide == secondSide && secondSide == thirdSide) {
return "equilateral";
}
return "scalene";
}std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
if (firstSide <= 0 || secondSide <= 0 || thirdSide <= 0) {
return "invalid";
}
if (firstSide + secondSide <= thirdSide || firstSide + thirdSide <= secondSide || secondSide + thirdSide <= firstSide) {
return "invalid";
}
if (firstSide == secondSide && secondSide == thirdSide) {
return "equilateral";
}
if (firstSide == secondSide) {
return "isosceles";
}
return "scalene";
}Voici une implémentation correcte de la fonction
classifyTrianglequi devrait passer tous les tests.
#include "triangle-classifier.h"
#include <string>
static bool isTriangleInvalid(int firstSide, int secondSide, int thirdSide) {
bool hasNonPositiveSide = (firstSide <= 0 || secondSide <= 0 || thirdSide <= 0);
bool violatesTriangleInequality = (firstSide + secondSide <= thirdSide) || (firstSide + thirdSide <= secondSide) || (secondSide + thirdSide <= firstSide);
return hasNonPositiveSide || violatesTriangleInequality;
}
static bool isTriangleEquilateral(int firstSide, int secondSide, int thirdSide) {
return firstSide == secondSide && secondSide == thirdSide;
}
static bool isTriangleIsosceles(int firstSide, int secondSide, int thirdSide) {
return firstSide == secondSide || firstSide == thirdSide || secondSide == thirdSide;
}
std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
std::string result = "scalene";
bool isInvalid = isTriangleInvalid(firstSide, secondSide, thirdSide);
bool isEquilateral = isTriangleEquilateral(firstSide, secondSide, thirdSide);
bool isIsosceles = isTriangleIsosceles(firstSide, secondSide, thirdSide);
if (isInvalid) {
result = "invalid";
}
if (!isInvalid && isEquilateral) {
result = "equilateral";
}
if (!isInvalid && !isEquilateral && isIsosceles) {
result = "isosceles";
}
return result;
}Écrire des tests unitaires
static voidsans arguments avec la conventionmethodName_StateUnderTest_ExpectedBehavior.Utiliser
assertdans les tests unitaires pour comparer la sortie attendue et la sortie obtenue d’une fonction.