implemented many unit tests

This commit is contained in:
Aaro Koivukangas
2025-05-10 16:58:50 +03:00
parent a63188d903
commit f2c7802a8e
11 changed files with 337 additions and 60 deletions
+45 -3
View File
@@ -1,6 +1,21 @@
cmake_minimum_required(VERSION 4.0)
project(ttk91_compiler C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 99)
# creates compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Googletest (aka gtest)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FetchContent_MakeAvailable(googletest)
# https://cmake.org/cmake/help/latest/module/FindBISON.html
find_package(BISON)
bison_target(
@@ -20,7 +35,6 @@ flex_target(
)
set(SOURCES
src/main.c
src/parser.c
src/scanner.c
src/program.c
@@ -32,6 +46,34 @@ set(SOURCES
src/comment.c
)
add_executable(ttk91_compiler ${SOURCES})
add_library(ttk91_compiler_lib ${SOURCES})
add_executable(ttk91_compiler src/main.c)
target_include_directories(ttk91_compiler PRIVATE include)
target_include_directories(ttk91_compiler PRIVATE include)
target_include_directories(ttk91_compiler_lib PRIVATE include)
target_link_libraries(ttk91_compiler ttk91_compiler_lib)
# Testing
enable_testing()
set(TESTING_SOURCES
test/comment.cpp
test/label.cpp
test/value.cpp
test/ttk_register.cpp
test/oper.cpp
test/expr.cpp
${SOURCES}
)
add_executable(tests ${TESTING_SOURCES})
target_link_libraries(
tests
GTest::gtest_main
)
target_include_directories(tests PRIVATE include)
include(GoogleTest)
gtest_discover_tests(tests)
+2
View File
@@ -1,6 +1,7 @@
#ifndef LABEL_H
#define LABEL_H
#include <stddef.h>
#include "expr.h"
typedef enum {
@@ -15,6 +16,7 @@ struct label {
};
struct label * label_create(label_t kind, char* name, int value);
int label_to_string(char* buffer, const size_t size, struct label *l);
int label_print_intel_asm(struct label *l);
int label_print(struct label *l);
+4
View File
@@ -1,6 +1,8 @@
#ifndef REGISTER_H
#define REGISTER_H
#include <stddef.h>
typedef enum {
TTK_REGISTER,
STACK_TTK_REGISTER
@@ -17,6 +19,8 @@ int parse_register_num(char *name, ttk_register_t kind);
struct ttk_register * ttk_register_create_register(char* name);
struct ttk_register * ttk_register_create_stack_register(char* name);
int ttk_register_to_string(char* buffer, size_t size, struct ttk_register *ttk_reg);
int ttk_register_to_intel_asm_string(char* buffer, size_t size, struct ttk_register *ttk_reg);
int ttk_register_print(struct ttk_register *ttk_reg);
int ttk_register_print_intel_asm(struct ttk_register *ttk_reg);
+22 -7
View File
@@ -23,6 +23,23 @@ struct label * label_create_const(char* name) { return label_create(LABEL_
struct label * label_create_const_sys(char* name) { return label_create(LABEL_CONST, name, 0); } // FIXME value
struct label * label_create_tag(char* name) { return label_create(LABEL_TAG, name, 0); } // FIXME also this
int label_to_string(char* buffer, size_t size, struct label *l) {
if (size < 2) {
printf("ERROR: Buffer size too small (label)\n");
return -1;
}
if (!l->name)
{
printf("ERROR: Label name doesn't exist.\n");
snprintf(buffer, size, "???");
return VARIABLE_NULL;
}
snprintf(buffer, size, "%s", l->name);
return 0;
}
int label_print_intel_asm(struct label *l)
{
return label_print(l);
@@ -30,18 +47,16 @@ int label_print_intel_asm(struct label *l)
int label_print(struct label *l)
{
if (!l->name)
{
printf("ERROR: Label name doesn't exist.\n");
return VARIABLE_NULL;
}
size_t size = 50;
char buffer[size];
printf("%s", l->name);
label_to_string(buffer, size, l);
printf("%s", buffer);
return 0;
}
void label_free(struct label *l)
{
if (l->name) free(l->name);
// if (l->name) free(l->name);
free(l);
}
+101 -50
View File
@@ -1,6 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include "error.h"
#include "ttk_register.h"
@@ -37,8 +39,8 @@ struct ttk_register * ttk_register_create_stack_register(char* name)
int parse_register_num(char* name, ttk_register_t kind)
{
if (!name) {
printf("Name null while parsing register name.\n");
if (!name || strcmp(name, "") == 0) {
printf("ERROR: Name null or empty while parsing register name.\n");
return -1;
}
@@ -49,87 +51,136 @@ int parse_register_num(char* name, ttk_register_t kind)
case TTK_REGISTER:
char num = name[1]; // registers have the format RX, 'R' + X 0-7
value = num - '0';
break;
case STACK_TTK_REGISTER:
if (strcasecmp("sp", name) == 0)
value = 6;
if (0 <= value && value <= 8)
break;
else
assert(false && "Incorrect register name value");
if (strcasecmp("fp", name) == 0)
case STACK_TTK_REGISTER:
value = -1;
if (strcasecmp("sp", name) == 0) {
value = 6;
break;
}
else if (strcasecmp("fp", name) == 0) {
value = 7;
break;
break;
}
else
assert(false && "Stack register not 6 or 7");
default:
free(name);
printf("Register type not matched while parsing register name.\n");
return -1;
assert(false && "Register kind not matched while parsing register name.");
break;
}
free(name);
return value;
}
int ttk_register_print_intel_asm(struct ttk_register *ttk_reg)
{
// EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI
if (!ttk_reg || !ttk_reg->id)
int ttk_register_to_string(char* buffer, size_t size, struct ttk_register *ttk_reg) {
if (size < 3) {
printf("ERROR: Buffer size too small (ttk_reg_to_string)\n");
return -1;
}
if (!ttk_reg)
{
printf("ttk_register missing while trying to print it.\n");
printf("ERROR: ttk_register missing while trying to print it.\n");
return VARIABLE_NULL;
}
switch (ttk_reg->id)
{
case 0:
case 1:
printf("eax");
break;
case 2:
printf("ebx");
break;
case 3:
printf("ecx");
break;
case 4:
printf("edx");
break;
case 5:
printf("esp");
snprintf(buffer, size, "R%d", ttk_reg->id);
break;
case 6:
printf("ebp");
snprintf(buffer, size, "SP");
break;
case 7:
printf("esi");
break;
case 0:
printf("edi"); // TODO: this is possibly not correct
snprintf(buffer, size, "FP");
break;
default:
printf("ERROR: No matching register\n");
return SWITCH_NOT_MATCHED;
assert(false && "No register id matched\n");
break;
}
return 0;
}
int ttk_register_to_intel_asm_string(char* buffer, size_t size, struct ttk_register *ttk_reg)
{
if (size < 5) {
printf("ERROR: Buffer size too small (ttk_reg_to_string)\n");
return -1;
}
if (!ttk_reg)
{
printf("ERROR: ttk_register missing while trying to print it.\n");
return VARIABLE_NULL;
}
// TODO: this is possibly not correct
// EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI
switch (ttk_reg->id)
{
case 1:
snprintf(buffer, size, "eax");
break;
case 2:
snprintf(buffer, size, "ebx");
break;
case 3:
snprintf(buffer, size, "ecx");
break;
case 4:
snprintf(buffer, size, "edx");
break;
case 5:
snprintf(buffer, size, "esp");
break;
case 6:
snprintf(buffer, size, "ebp");
break;
case 7:
snprintf(buffer, size, "esi");
break;
case 0:
snprintf(buffer, size, "edi");
break;
default:
assert(false && "No matching register");
break;
}
return 0;
}
int ttk_register_print_intel_asm(struct ttk_register *ttk_reg)
{
size_t size = 5;
char buffer[size];
ttk_register_to_intel_asm_string(buffer, size, ttk_reg);
printf("%s", buffer);
return 0;
}
int ttk_register_print(struct ttk_register *ttk_reg)
{
if (!ttk_reg || !ttk_reg->id)
{
printf("ttk_register missing while trying to print it.\n");
return VARIABLE_NULL;
}
switch (ttk_reg->id)
{
case 6:
printf("SP");
return 0;
case 7:
printf("FP");
return 0;
default:
break;
}
size_t size = 3;
char buffer[size];
printf("R%d", ttk_reg->id);
ttk_register_to_string(buffer, size, ttk_reg);
printf("%s", buffer);
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
#include <gtest/gtest.h>
extern "C" {
#include "comment.h"
}
TEST(Test_comments, Test_comments_TODO) {
}
+9
View File
@@ -0,0 +1,9 @@
#include <gtest/gtest.h>
extern "C" {
#include "expr.h"
}
TEST(Test_expressions, Test_expr_TODO) {
}
+18
View File
@@ -0,0 +1,18 @@
#include <gtest/gtest.h>
extern "C" {
#include "label.h"
}
TEST(Test_labels, Test_label_print_with_valid_parameter) {
const size_t size = 10;
char buffer[size];
char label_name[] = "X";
struct label *l = label_create_const(label_name);
label_to_string(buffer, size, l);
EXPECT_STREQ(label_name, buffer);
label_free(l);
}
+9
View File
@@ -0,0 +1,9 @@
#include <gtest/gtest.h>
extern "C" {
#include "oper.h"
}
TEST(Test_opers, Test_opers_TODO) {
}
+109
View File
@@ -0,0 +1,109 @@
#include <gtest/gtest.h>
extern "C" {
#include "ttk_register.h"
#include "error.h"
}
TEST(Test_ttk_registers, parse_register_num_fails_with_empty_name) {
char empty_name[] = "";
char* null_name = NULL;
const ttk_register_t kind = TTK_REGISTER;
int result_empty = parse_register_num(empty_name, kind);
int result_null = parse_register_num(null_name, kind);
EXPECT_EQ(-1, result_empty);
EXPECT_EQ(-1, result_null);
}
TEST(Test_ttk_registers, parse_register_num_returns_correct_value_ttk_reg) {
char name0[] = "R0";
char name3[] = "R3";
char name6[] = "R6"; // also SP
const ttk_register_t kind = TTK_REGISTER;
int result0 = parse_register_num(name0, kind);
int result3 = parse_register_num(name3, kind);
int result6 = parse_register_num(name6, kind);
EXPECT_EQ(0, result0);
EXPECT_EQ(3, result3);
EXPECT_EQ(6, result6);
}
TEST(Test_ttk_registers, parse_register_num_returns_correct_value_stack_registers) {
char name_sp[] = "SP";
char name_fp[] = "FP";
const ttk_register_t kind = STACK_TTK_REGISTER;
int result_sp = parse_register_num(name_sp, kind);
int result_fp = parse_register_num(name_fp, kind);
EXPECT_EQ(result_sp, 6);
EXPECT_EQ(result_fp, 7);
}
TEST(Test_ttk_registers, Test_ttk_register_to_string_valid_parameters) {
const size_t size = 3;
char buffer0[size];
char buffer2[size];
char buffer7[size];
char reg_name0[] = "R0";
char reg_name2[] = "R2";
char reg_name7[] = "R7";
struct ttk_register *ttk_reg0 = ttk_register_create_register(reg_name0);
struct ttk_register *ttk_reg2 = ttk_register_create_register(reg_name2);
struct ttk_register *ttk_reg7 = ttk_register_create_register(reg_name7);
EXPECT_EQ(0, ttk_reg0->id);
EXPECT_EQ(2, ttk_reg2->id);
EXPECT_EQ(7, ttk_reg7->id);
int res0 = ttk_register_to_string(buffer0, size, ttk_reg0);
int res2 = ttk_register_to_string(buffer2, size, ttk_reg2);
int res7 = ttk_register_to_string(buffer7, size, ttk_reg7);
EXPECT_EQ(0, res0);
EXPECT_EQ(0, res2);
EXPECT_EQ(0, res7);
EXPECT_STREQ("R0", buffer0);
EXPECT_STREQ("R2", buffer2);
EXPECT_STREQ("FP", buffer7);
ttk_register_free(ttk_reg0);
ttk_register_free(ttk_reg2);
ttk_register_free(ttk_reg7);
}
TEST(Test_ttk_registers, Test_ttk_register_to_string_too_small_buffer_size) {
const size_t size = 2;
char buffer0[size];
char reg_name0[] = "R0";
struct ttk_register *ttk_reg0 = ttk_register_create_register(reg_name0);
EXPECT_EQ(0, ttk_reg0->id);
// size and buffer too small
int res0 = ttk_register_to_string(buffer0, size, ttk_reg0);
EXPECT_EQ(-1, res0);
ttk_register_free(ttk_reg0);
}
TEST(Test_ttk_registers, Test_ttk_register_to_intel_asm_string_too_small_buffer_size) {
const size_t size = 4;
char buffer[size];
char reg_name[] = "R2";
struct ttk_register *ttk_reg = ttk_register_create_register(reg_name);
EXPECT_EQ(2, ttk_reg->id);
int result = ttk_register_to_intel_asm_string(buffer, size, ttk_reg);
EXPECT_EQ(-1, result);
ttk_register_free(ttk_reg);
}
+9
View File
@@ -0,0 +1,9 @@
#include <gtest/gtest.h>
extern "C" {
#include "value.h"
}
TEST(Test_values, Test_value_TODO) {
}