Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

TriangleClassifier

  1. Create the Lab9/ directory with the following structure:

Lab9/
├── include/
│    └── triangle-classifier.h
├── source/
│    ├── triangle-classifier.cpp
│    └── main.cpp
├── tests/
│    ├── include/
│    │    └── triangle-classifier-test.h
│    └── source/
│         ├── triangle-classifier-test.cpp
│         └── main.cpp
└── makefile
  1. Copy the following code into the different files.

makefile
triangle-classifier.cpp
triangle-classifier.h
source/main.cpp
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)
triangle-classifier-test.cpp
triangle-classifier-test.h
tests/source/main.cpp
#include "triangle-classifier.h"
#include "triangle-classifier-test.h"
#include <iostream>
#include <cassert>

void TriangleClassifierTest::runTests() {
	std::cout << "All tests passed\n";
}
  1. Read the documentation for the TriangleClassifier class.

  2. Implement the tests for the classifyTriangle function in triangle-classifier-test.cpp.

  3. If you have written your tests correctly, the following incorrect implementations of classifyTriangle should not pass all of the tests:

Negative side not handled
a single triangle inequality
An equilateral triangle is isosceles?
a single side handled
std::string TriangleClassifier::classifyTriangle(int firstSide, int secondSide, int thirdSide) {
	if (firstSide == secondSide) {
		return "isosceles";
	}

	if (firstSide == secondSide && secondSide == thirdSide) {
		return "equilateral";
	}

	return "scalene";
}
  1. The following is a correct implementation of the classifyTriangle function that should pass all of the tests.

triangle-classifier.cpp
#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;
}
Key takeaways
  • Write unit tests as static void methods without parameters using the methodName_StateUnderTest_ExpectedBehavior convention.

  • Use assert in unit tests to compare the expected output with the actual output of a function.