1
Fork 0

Initial Commit

This commit is contained in:
Guillem 2022-04-01 15:58:20 +02:00
commit 5dea15d7a2
Signed by: lordwektabyte
GPG key ID: 73C5458905782129
24 changed files with 3160 additions and 0 deletions

19
.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
# CodeLite IDE
*.mk
*.txt
#*.project
#*.workspace
compile_commands.json
Makefile
.codelite/
*.session
*.tags
tags
# Builds
Debug/
Release/
.build-debug/
.build-release/
bin/
lib/

4
UOC20212/README.txt Normal file
View file

@ -0,0 +1,4 @@
gsboeck@uoc.edu
Solà i Boeck , Guillem
Fedora release 35 (Thirty Five) x86_64
gcc version 11.2.1 20220127 (Red Hat 11.2.1-9) (GCC)

132
UOC20212/UOC20212.project Normal file
View file

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="UOC20212" Version="11000" InternalType="Console">
<Plugins>
<Plugin Name="qmake">
<![CDATA[00020001N0005Debug0000000000000001N0007Release000000000000]]>
</Plugin>
</Plugins>
<VirtualDirectory Name="test">
<VirtualDirectory Name="include">
<File Name="test/include/test_pr1.h"/>
<File Name="test/include/test_data.h"/>
<File Name="test/include/test.h"/>
<File Name="test/include/test_suite.h"/>
</VirtualDirectory>
<VirtualDirectory Name="src">
<File Name="test/src/test_pr1.c"/>
<File Name="test/src/test.c"/>
<File Name="test/src/test_suite.c"/>
</VirtualDirectory>
</VirtualDirectory>
<Description/>
<Dependencies/>
<VirtualDirectory Name="src">
<File Name="src/main.c"/>
</VirtualDirectory>
<Dependencies Name="Debug">
<Project Name="UOCVaccine"/>
</Dependencies>
<Dependencies Name="Release">
<Project Name="UOCVaccine"/>
</Dependencies>
<Settings Type="Executable">
<GlobalSettings>
<Compiler Options="" C_Options="" Assembler="">
<IncludePath Value="."/>
</Compiler>
<Linker Options="">
<LibraryPath Value="."/>
</Linker>
<ResourceCompiler Options=""/>
</GlobalSettings>
<Configuration Name="Debug" CompilerType="GCC" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g;-O0;-Wall" C_Options="-g;-O0;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="test/include"/>
<IncludePath Value="UOCVaccine/include"/>
</Compiler>
<Linker Options="" Required="yes">
<LibraryPath Value="./lib"/>
<Library Value="libUOCVaccined.a"/>
</Linker>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="./bin/$(ProjectName)d" IntermediateDirectory="$(ConfigurationName)" Command="$(ProjectName)d" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="./bin" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<BuildSystem Name="Default"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="no">
<RebuildCommand/>
<CleanCommand/>
<BuildCommand/>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory/>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
<Configuration Name="Release" CompilerType="GCC" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-O2;-Wall" C_Options="-O2;-Wall" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="test/include"/>
<IncludePath Value="UOCVaccine/include"/>
<Preprocessor Value="NDEBUG"/>
</Compiler>
<Linker Options="" Required="yes">
<LibraryPath Value="./lib"/>
<Library Value="libUOCVaccine.a"/>
</Linker>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="./bin/$(ProjectName)" IntermediateDirectory="$(ConfigurationName)" Command="$(ProjectName)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="./bin" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<BuildSystem Name="Default"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="no">
<RebuildCommand/>
<CleanCommand/>
<BuildCommand/>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName>None</ThirdPartyToolName>
<WorkingDirectory/>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
</Settings>
</CodeLite_Project>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="UOC20212" Database="" Version="10000">
<Project Name="UOC20212" Path="UOC20212.project" Active="Yes"/>
<Project Name="UOCVaccine" Path="UOCVaccine/UOCVaccine.project" Active="No"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Environment/>
<Project Name="UOC20212" ConfigName="Debug"/>
<Project Name="UOCVaccine" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Environment/>
<Project Name="UOC20212" ConfigName="Release"/>
<Project Name="UOCVaccine" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>

View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="UOCVaccine" Version="11000" InternalType="Library">
<Plugins>
<Plugin Name="qmake">
<![CDATA[00010001N0005Debug000000000000]]>
</Plugin>
</Plugins>
<Description/>
<Dependencies/>
<VirtualDirectory Name="src">
<File Name="src/vaccine.c"/>
<File Name="src/person.c"/>
<File Name="src/date.c"/>
<File Name="src/csv.c"/>
<File Name="src/api.c"/>
</VirtualDirectory>
<VirtualDirectory Name="include">
<File Name="include/vaccine.h"/>
<File Name="include/person.h"/>
<File Name="include/error.h"/>
<File Name="include/date.h"/>
<File Name="include/csv.h"/>
<File Name="include/api.h"/>
</VirtualDirectory>
<Settings Type="Static Library">
<GlobalSettings>
<Compiler Options="" C_Options="" Assembler="">
<IncludePath Value="."/>
</Compiler>
<Linker Options="">
<LibraryPath Value="."/>
</Linker>
<ResourceCompiler Options=""/>
</GlobalSettings>
<Configuration Name="Debug" CompilerType="GCC" DebuggerType="GNU gdb debugger" Type="Static Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="-g" C_Options="-g" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="include"/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="../lib/lib$(ProjectName)d.a" IntermediateDirectory="../$(ConfigurationName)" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<BuildSystem Name="Default"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="no">
<RebuildCommand/>
<CleanCommand/>
<BuildCommand/>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName/>
<WorkingDirectory/>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
<Configuration Name="Release" CompilerType="GCC" DebuggerType="GNU gdb debugger" Type="Static Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
<Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="include"/>
</Compiler>
<Linker Options="" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="../lib/lib$(ProjectName).a" IntermediateDirectory="../$(ConfigurationName)" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
<BuildSystem Name="Default"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
<PreBuild/>
<PostBuild/>
<CustomBuild Enabled="no">
<RebuildCommand/>
<CleanCommand/>
<BuildCommand/>
<PreprocessFileCommand/>
<SingleFileCommand/>
<MakefileGenerationCommand/>
<ThirdPartyToolName/>
<WorkingDirectory/>
</CustomBuild>
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
<Completion EnableCpp11="no" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
</Configuration>
</Settings>
</CodeLite_Project>

View file

@ -0,0 +1,63 @@
#ifndef __UOCVACCINE_API__H
#define __UOCVACCINE_API__H
#include <stdbool.h>
#include "error.h"
#include "csv.h"
#include "person.h"
#include "vaccine.h"
// Type that stores all the application data
typedef struct _ApiData {
////////////////////////////////
// PR1 EX2a
////////////////////////////////
tPopulation population;
tVaccineList vaccines;
tVaccineLotData vaccineLots;
} tApiData;
// Get the API version information
const char* api_version();
// Load data from a CSV file. If reset is true, remove previous data
tApiError api_loadData(tApiData* data, const char* filename, bool reset);
// Add a new entry
tApiError api_addDataEntry(tApiData* data, tCSVEntry entry);
// Free all used memory
tApiError api_freeData(tApiData* data);
// Initialize the data structure
tApiError api_initData(tApiData* data);
// Add a new vaccines lot
tApiError api_addVaccineLot(tApiData* data, tCSVEntry entry);
// Get the number of persons registered on the application
int api_populationCount(tApiData data);
// Get the number of vaccines registered on the application
int api_vaccineCount(tApiData data);
// Get the number of vaccine lots registered on the application
int api_vaccineLotsCount(tApiData data);
// Get vaccine data
tApiError api_getVaccine(tApiData data, const char *name, tCSVEntry *entry);
// Get vaccine lot data
tApiError api_getVaccineLot(tApiData data, const char* cp, const char* vaccine, tDateTime timestamp, tCSVEntry *entry);
// Get registered vaccines
tApiError api_getVaccines(tApiData data, tCSVData *vaccines);
// Get vaccine lots
tApiError api_getVaccineLots(tApiData data, tCSVData *lots);
#endif // __UOCVACCINE_API__H

View file

@ -0,0 +1,78 @@
#ifndef __CSV_H__
#define __CSV_H__
#include <stdbool.h>
#define CSV_SEPARATOR_CHAR ;
// Store one entry from a CSV file
typedef struct _tCSVEntry {
int numFields;
char* type;
char** fields;
} tCSVEntry;
// Store the content of a CSV file
typedef struct _tCSVData {
tCSVEntry *entries;
int count;
bool isValid;
} tCSVData;
// Initialize the tCSVData structure
void csv_init(tCSVData* data);
// Initialize the tCSVEntry structure
void csv_initEntry(tCSVEntry* entry);
// Parse the contents of a CSV file
void csv_parse(tCSVData* data, const char* input, const char* type);
// Add a new entry to the CSV Data
void csv_addStrEntry(tCSVData* data, const char* entry, const char* type);
// Print the content of the CSV data structure
void csv_print(tCSVData data);
// Print the content of the CSV entry structure
void csv_printEntry(tCSVEntry entry);
// Parse the contents of a CSV line "f1;f2;f3" => field_0 = f1, field_1 = f2, field_2 = f3
void csv_parseEntry(tCSVEntry* entry, const char* input, const char* type);
// Get the number of entries
bool csv_isValid(tCSVData data);
// Remove all data from structure
void csv_free(tCSVData* data);
// Remove all data from structure
void csv_freeEntry(tCSVEntry* entry);
// Get the number of entries
int csv_numEntries(tCSVData data);
// Get the type of information contained in the entry
const char* csv_getType(tCSVEntry* entry);
// Get an entry from the CSV data
tCSVEntry* csv_getEntry(tCSVData data, int position);
// Get the number of fields for a given entry
int csv_numFields(tCSVEntry entry);
// Get a field from the given entry as integer
int csv_getAsInteger(tCSVEntry entry, int position);
// Get a field from the given entry as string. The value is copied to the provided buffer with provided maximum length
void csv_getAsString(tCSVEntry entry, int position, char* buffer, int length);
// Get a field from the given entry as integer
float csv_getAsReal(tCSVEntry entry, int position);
// Compare if two entries are the same
bool csv_equalsEntry(tCSVEntry entry1, tCSVEntry entry2);
// Compare if two data objects are the same
bool csv_equals(tCSVData data1, tCSVData data2);
#endif

View file

@ -0,0 +1,31 @@
#ifndef __DATE_H__
#define __DATE_H__
#include <stdbool.h>
typedef struct _tDate {
int day;
int month;
int year;
} tDate;
typedef struct _tTime {
int hour;
int minutes;
} tTime;
typedef struct _tDateTime {
tDate date;
tTime time;
} tDateTime;
// Parse a tDateTime from string information
void dateTime_parse(tDateTime* dateTime, const char* date, const char* time);
// Compare two tDateTime structures and return -1 if dateTime1<dateTime2, 0 if equals and 1 if dateTime1>dateTime2.
int dateTime_cmp(tDateTime dateTime1, tDateTime dateTime2);
// Compare two tDateTime structures and return true if they contain the same value or false otherwise.
bool dateTime_equals(tDateTime dateTime1, tDateTime dateTime2);
#endif // __DATE_H__

View file

@ -0,0 +1,23 @@
#ifndef __UOCCONTACTS_ERROR__H
#define __UOCCONTACTS_ERROR__H
// Define error codes
enum _tApiError
{
E_SUCCESS = 0, // No error
E_NOT_IMPLEMENTED = -1, // Called method is not implemented
E_FILE_NOT_FOUND = -2, // File not found
E_PERSON_NOT_FOUND = -3, // Person not found
E_INVALID_ENTRY_TYPE = -4, // Invalid entry type
E_INVALID_ENTRY_FORMAT = -5, // Invalid entry format
E_DUPLICATED_PERSON = -6, // Duplicated person
E_MEMORY_ERROR = -7, // Memory error
E_VACCINE_NOT_FOUND = -8, // Vaccine not found
E_HEALTH_CENTER_NOT_FOUND = -9, // Health Center not found
E_LOT_NOT_FOUND = -10, // Vaccine lot not found
};
// Define an error type
typedef enum _tApiError tApiError;
#endif // __UOCCONTACTS_ERRORS__H

View file

@ -0,0 +1,54 @@
#ifndef __PERSON_H__
#define __PERSON_H__
#include "csv.h"
#include "date.h"
typedef struct _tPerson {
char* document;
char* name;
char* surname;
char* cp;
char* email;
char* address;
tDate birthday;
} tPerson;
typedef struct _tPopulation {
tPerson* elems;
int count;
} tPopulation;
// Initialize the population data
void population_init(tPopulation* data);
// Initialize a person structure
void person_init(tPerson* data);
// Remove the data from a person
void person_free(tPerson* data);
// Remove the data from all persons
void population_free(tPopulation* data);
// Parse input from CSVEntry
void person_parse(tPerson* data, tCSVEntry entry);
// Add a new person
void population_add(tPopulation* data, tPerson person);
// Remove a person
void population_del(tPopulation* data, const char *document);
// Return the position of a person with provided document. -1 if it does not exist
int population_find(tPopulation data, const char* document);
// Print the person data
void population_print(tPopulation data);
// Copy the data from the source to destination
void person_cpy(tPerson* destination, tPerson source);
// Return population lenght
int population_len(tPopulation data);
#endif

View file

@ -0,0 +1,106 @@
#ifndef __VACCINE__H
#define __VACCINE__H
#include "csv.h"
#include "date.h"
// Vaccine data
typedef struct _tVaccine {
char *name;
int required;
int days;
} tVaccine;
// Node of a list of vaccines
typedef struct _tVaccineNode {
tVaccine vaccine;
struct _tVaccineNode *next;
} tVaccineNode;
// List of vaccines
typedef struct _tVaccineList {
tVaccineNode* first;
int count;
} tVaccineList;
// Vaccine lot data
typedef struct _tVaccineLot {
tVaccine* vaccine;
tDateTime timestamp;
char *cp;
int doses;
} tVaccineLot;
// Table of lots
typedef struct _tVaccineLotData {
tVaccineLot* elems;
int count;
} tVaccineLotData;
// Initialize vaccine structure
void vaccine_init(tVaccine* vaccine, const char* name, int required, int days);
// Release vaccine data
void vaccine_free(tVaccine* vaccine);
// Copy the data of a vaccine from the source to destination
void vaccine_cpy(tVaccine* destination, tVaccine source);
// Release vaccine lot data
void vaccineLot_init(tVaccineLot* lot, tVaccine* vaccine, const char* cp, tDateTime timestamp, int doses);
// Release vaccine lot data
void vaccineLot_free(tVaccineLot* lot);
// Copy the data of a vaccine lot from the source to destination
void vaccineLot_cpy(tVaccineLot* destination, tVaccineLot source);
// Parse input from CSVEntry
void vaccineLot_parse(tVaccine* vaccine, tVaccineLot* lot, tCSVEntry entry);
// Initialize the vaccine's list
void vaccineList_init(tVaccineList* list);
// Remove all elements
void vaccineList_free(tVaccineList* list);
// Get the number of vaccines
int vaccineList_len(tVaccineList list);
// Find a vaccine in the list of vaccines
tVaccine* vaccineList_find(tVaccineList list, const char* name);
// Add a new vaccine
void vaccineList_insert(tVaccineList* list, tVaccine vaccine);
// Remove a vaccine
void vaccineList_del(tVaccineList* list, const char* vaccine);
// Initialize the vaccine lots data
void vaccineLotData_init(tVaccineLotData* data);
// Remove all elements
void vaccineLotData_free(tVaccineLotData* data);
// Get the number of lots
int vaccineLotData_len(tVaccineLotData data);
// Add a new vaccine lot
void vaccineLotData_add(tVaccineLotData* data, tVaccineLot lot);
// Remove vaccines from a lot
void vaccineLotData_del(tVaccineLotData* data, const char* cp, const char* vaccine, tDateTime timestamp, int doses);
// Return the position of a vaccine lot entry with provided information. -1 if it does not exist
int vaccineLotData_find(tVaccineLotData data, const char* cp, const char* vaccine, tDateTime timestamp);
#endif // __VACCINE__H

View file

@ -0,0 +1,185 @@
#include <stdio.h>
#include <assert.h>
#include "csv.h"
#include "api.h"
#include <string.h>
#include "person.h"
#include "vaccine.h"
#define FILE_READ_BUFFER_SIZE 2048
#define VACCINE_LOT_TYPE_NAME "VACCINE_LOT"
#define VACCINE_LOT_NUM_FIELDS 7
// Get the API version information
const char* api_version() {
return "UOC PP 20212";
}
// Load data from a CSV file. If reset is true, remove previous data
tApiError api_loadData(tApiData* data, const char* filename, bool reset) {
tApiError error;
FILE *fin;
char buffer[FILE_READ_BUFFER_SIZE];
tCSVEntry entry;
// Check input data
assert( data != NULL );
assert(filename != NULL);
// Reset current data
if (reset) {
// Remove previous information
error = api_freeData(data);
if (error != E_SUCCESS) {
return error;
}
// Initialize the data
error = api_initData(data);
if (error != E_SUCCESS) {
return error;
}
}
// Open the input file
fin = fopen(filename, "r");
if (fin == NULL) {
return E_FILE_NOT_FOUND;
}
// Read file line by line
while (fgets(buffer, FILE_READ_BUFFER_SIZE, fin)) {
// Remove new line character
buffer[strcspn(buffer, "\n\r")] = '\0';
csv_initEntry(&entry);
csv_parseEntry(&entry, buffer, NULL);
// Add this new entry to the api Data
error = api_addDataEntry(data, entry);
if (error != E_SUCCESS) {
return error;
}
csv_freeEntry(&entry);
}
fclose(fin);
return E_SUCCESS;
}
// Initialize the data structure
tApiError api_initData(tApiData* data) {
//////////////////////////////////
// Ex PR1 2b
/////////////////////////////////
population_init(&(data->population));
vaccineList_init(&(data->vaccines));
vaccineLotData_init(&(data->vaccineLots));
return E_SUCCESS;
}
// Add a new vaccines lot
tApiError api_addVaccineLot(tApiData* data, tCSVEntry entry) {
//////////////////////////////////
// Ex PR1 2c
/////////////////////////////////
tApiError ret = E_NOT_IMPLEMENTED;
if (csv_numFields(entry) == VACCINE_LOT_NUM_FIELDS) {
if (csv_getType(&entry) == VACCINE_LOT_TYPE_NAME) {
// OK
ret = E_SUCCESS;
} else {
// numFields other than valid one
ret = E_INVALID_ENTRY_TYPE;
}
} else {
// csv record type other than valid one
ret = E_INVALID_ENTRY_FORMAT;
}
return ret;
}
// Get the number of persons registered on the application
int api_populationCount(tApiData data) {
//////////////////////////////////
// Ex PR1 2d
/////////////////////////////////
return -1;
}
// Get the number of vaccines registered on the application
int api_vaccineCount(tApiData data) {
//////////////////////////////////
// Ex PR1 2d
/////////////////////////////////
return -1;
}
// Get the number of vaccine lots registered on the application
int api_vaccineLotsCount(tApiData data) {
//////////////////////////////////
// Ex PR1 2d
/////////////////////////////////
return -1;
}
// Free all used memory
tApiError api_freeData(tApiData* data) {
//////////////////////////////////
// Ex PR1 2e
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}
// Add a new entry
tApiError api_addDataEntry(tApiData* data, tCSVEntry entry) {
//////////////////////////////////
// Ex PR1 2f
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}
// Get vaccine data
tApiError api_getVaccine(tApiData data, const char *name, tCSVEntry *entry) {
//////////////////////////////////
// Ex PR1 3a
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}
// Get vaccine lot data
tApiError api_getVaccineLot(tApiData data, const char* cp, const char* vaccine, tDateTime timestamp, tCSVEntry *entry) {
//////////////////////////////////
// Ex PR1 3b
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}
// Get registered vaccines
tApiError api_getVaccines(tApiData data, tCSVData *vaccines) {
//////////////////////////////////
// Ex PR1 3c
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}
// Get vaccine lots
tApiError api_getVaccineLots(tApiData data, tCSVData *lots) {
//////////////////////////////////
// Ex PR1 3d
/////////////////////////////////
return E_NOT_IMPLEMENTED;
}

View file

@ -0,0 +1,265 @@
#include "csv.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
// Initialize the tCSVData structure
void csv_init(tCSVData* data) {
data->count = 0;
data->isValid = false;
data->entries = NULL;
}
// Initialize the tCSVEntry structure
void csv_initEntry(tCSVEntry* entry) {
entry->numFields = 0;
entry->fields = NULL;
entry->type = NULL;
}
// Add a new entry to the CSV Data
void csv_addStrEntry(tCSVData* data, const char* entry, const char* type) {
assert( data != NULL );
assert( entry != NULL );
data->count++;
if (data->count == 1) {
data->entries = (tCSVEntry*) malloc(sizeof(tCSVEntry));
} else {
data->entries = (tCSVEntry*) realloc(data->entries, data->count * sizeof(tCSVEntry));
}
csv_initEntry(&(data->entries[data->count-1]));
csv_parseEntry(&(data->entries[data->count-1]), entry, type);
}
// Parse the contents of a CSV file
void csv_parse(tCSVData* data, const char* input, const char* type) {
const char *pStart, *pEnd;
char *line;
int len;
assert(data->count == 0);
assert(data->entries == NULL);
assert(!data->isValid);
pStart = input;
pEnd = strchr(pStart, '\n');
while(pEnd != NULL && pEnd != pStart) {
len = pEnd - pStart + 1;
line = (char*) malloc(len * sizeof(char));
memset(line, 0, len * sizeof(char));
strncpy(line, pStart, pEnd - pStart);
// Add the new entry line
csv_addStrEntry(data, line, type);
free(line);
pStart = pEnd + 1;
pEnd = strchr(pStart, '\n');
}
pEnd = strchr(pStart, '\0');
if (pEnd != NULL && pEnd != pStart) {
len = pEnd - pStart + 1;
line = (char*) malloc(len * sizeof(char));
memset(line, 0, len * sizeof(char));
strncpy(line, pStart, pEnd - pStart);
data->count++;
if (data->count == 1) {
data->entries = (tCSVEntry*) malloc(sizeof(tCSVEntry));
} else {
data->entries = (tCSVEntry*) realloc(data->entries, data->count * sizeof(tCSVEntry));
}
csv_initEntry(&(data->entries[data->count-1]));
csv_parseEntry(&(data->entries[data->count-1]), line, type);
free(line);
}
data->isValid = true;
}
// Print the content of the CSV data structure
void csv_print(tCSVData data) {
int i;
tCSVEntry* entry = NULL;
for (i = 0; i < csv_numEntries(data); i++) {
entry = csv_getEntry(data, i);
printf("===============\n");
printf("Entry %d: %s\n", i, entry->type);
printf("===============\n");
csv_printEntry(*entry);
printf("===============\n");
}
}
// Print the content of the CSV entry structure
void csv_printEntry(tCSVEntry entry) {
int i;
char buffer[512];
printf("\tNum Fields: %d\n", csv_numFields(entry));
for (i = 0; i < csv_numFields(entry); i++) {
csv_getAsString(entry, i, buffer, 512);
printf("\tField %d: %s\n", i, buffer);
}
}
// Parse the contents of a CSV line
void csv_parseEntry(tCSVEntry* entry, const char* input, const char* type) {
const char *pStart, *pEnd;
int len;
bool readType = true;
assert(entry->numFields == 0);
assert(entry->fields == NULL);
// If the type of the entry is not provided, use the first field
if(type != NULL) {
len = strlen(type) + 1;
entry->type = (char*) malloc(len * sizeof(char));
memset(entry->type, 0, len * sizeof(char));
strncpy(entry->type, type, len);
readType = false;
}
pStart = input;
pEnd = strchr(pStart, ';');
while(pEnd != NULL && pEnd != pStart) {
// Get the length of the field
len = pEnd - pStart + 1;
if(readType) {
entry->type = (char*) malloc(len * sizeof(char));
memset(entry->type, 0, len * sizeof(char));
strncpy(entry->type, pStart, pEnd - pStart);
readType = false;
} else {
entry->numFields++;
if (entry->numFields == 1) {
entry->fields = (char**) malloc(sizeof(char*));
} else {
entry->fields = (char**) realloc(entry->fields, entry->numFields * sizeof(char*));
}
entry->fields[entry->numFields - 1] = (char*) malloc(len * sizeof(char));
memset(entry->fields[entry->numFields - 1], 0, len * sizeof(char));
strncpy(entry->fields[entry->numFields - 1], pStart, pEnd - pStart);
}
pStart = pEnd + 1;
pEnd = strchr(pStart, ';');
}
pEnd = strchr(pStart, '\0');
if (pEnd != NULL && pEnd != pStart) {
assert(!readType);
entry->numFields++;
if (entry->numFields == 1) {
entry->fields = (char**) malloc(sizeof(char*));
} else {
entry->fields = (char**) realloc(entry->fields, entry->numFields * sizeof(char*));
}
len = pEnd - pStart + 1;
entry->fields[entry->numFields - 1] = (char*) malloc(len * sizeof(char));
memset(entry->fields[entry->numFields - 1], 0, len * sizeof(char));
strncpy(entry->fields[entry->numFields - 1], pStart, pEnd - pStart);
}
}
// Get the number of entries
bool csv_isValid(tCSVData data) {
return data.isValid;
}
// Remove all data from structure
void csv_free(tCSVData* data) {
int i;
for (i = 0; i < data->count; i++) {
csv_freeEntry(&(data->entries[i]));
}
free(data->entries);
csv_init(data);
}
// Remove all data from structure
void csv_freeEntry(tCSVEntry* entry) {
int i;
if(entry->fields != NULL) {
for(i = 0; i < entry->numFields; i++) {
free(entry->fields[i]);
entry->fields[i] = NULL;
}
free(entry->fields);
}
if(entry->type != NULL) {
free(entry->type);
}
csv_initEntry(entry);
}
// Get the number of entries
int csv_numEntries(tCSVData data) {
return data.count;
}
// Get the type of information contained in the entry
const char* csv_getType(tCSVEntry* entry) {
return (const char*)entry->type;
}
// Get an entry from the CSV data
tCSVEntry* csv_getEntry(tCSVData data, int position) {
return &(data.entries[position]);
}
// Get the number of fields for a given entry
int csv_numFields(tCSVEntry entry) {
return entry.numFields;
}
// Get a field from the given entry as integer
int csv_getAsInteger(tCSVEntry entry, int position) {
return atoi(entry.fields[position]);
}
// Get a field from the given entry as string
void csv_getAsString(tCSVEntry entry, int position, char* buffer, int length) {
memset(buffer, 0, length);
strncpy(buffer, entry.fields[position], length - 1);
}
// Get a field from the given entry as integer
float csv_getAsReal(tCSVEntry entry, int position) {
return atof(entry.fields[position]);
}
// Compare if two entries are the same
bool csv_equalsEntry(tCSVEntry entry1, tCSVEntry entry2) {
int i;
if (entry1.numFields != entry2.numFields) {
return false;
}
if (strcmp(entry1.type, entry2.type) != 0) {
return false;
}
for (i = 0; i < entry1.numFields ; i++) {
if (strcmp(entry1.fields[i], entry2.fields[i]) != 0) {
return false;
}
}
return true;
}
// Compare if two data objects are the same
bool csv_equals(tCSVData data1, tCSVData data2) {
int i;
if (data1.count != data2.count) {
return false;
}
for (i = 0; i < data1.count ; i++) {
if (!csv_equalsEntry(data1.entries[i], data2.entries[i])) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,71 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "date.h"
// Parse a tDateTime from string information
void dateTime_parse(tDateTime* dateTime, const char* date, const char* time) {
// Check output data
assert(dateTime != NULL);
// Check input date
assert(date != NULL);
assert(strlen(date) == 10);
// Check input time
assert(time != NULL);
assert(strlen(time) == 5);
// Parse the input date
sscanf(date, "%d/%d/%d", &(dateTime->date.day), &(dateTime->date.month), &(dateTime->date.year));
// Parse the input time
sscanf(time, "%d:%d", &(dateTime->time.hour), &(dateTime->time.minutes));
}
// Compare two tDateTime structures and return -1 if dateTime1<dateTime2, 0 if equals and 1 if dateTime1>dateTime2.
int dateTime_cmp(tDateTime dateTime1, tDateTime dateTime2) {
// Checkl year
if (dateTime1.date.year < dateTime2.date.year) {
return -1;
}
if (dateTime1.date.year > dateTime2.date.year) {
return 1;
}
// Check month
if (dateTime1.date.month < dateTime2.date.month) {
return -1;
}
if (dateTime1.date.month > dateTime2.date.month) {
return 1;
}
// Check day
if (dateTime1.date.day < dateTime2.date.day) {
return -1;
}
if (dateTime1.date.day > dateTime2.date.day) {
return 1;
}
// Check hour
if (dateTime1.time.hour < dateTime2.time.hour) {
return -1;
}
if (dateTime1.time.hour > dateTime2.time.hour) {
return 1;
}
// Check minutes
if (dateTime1.time.minutes < dateTime2.time.minutes) {
return -1;
}
if (dateTime1.time.minutes > dateTime2.time.minutes) {
return 1;
}
return 0;
}
// Compare two tDateTime structures and return true if they contain the same value or false otherwise.
bool dateTime_equals(tDateTime dateTime1, tDateTime dateTime2) {
return dateTime_cmp(dateTime1, dateTime2) == 0;
}

View file

@ -0,0 +1,272 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "person.h"
// Initialize the population data
void population_init(tPopulation* data) {
// Check input/output data
assert(data != NULL);
data->elems = NULL;
data->count = 0;
}
// Initialize a person structure
void person_init(tPerson* data) {
// Check input data
assert(data != NULL);
data->document = NULL;
data->name = NULL;
data->surname = NULL;
data->email = NULL;
data->address = NULL;
data->cp = NULL;
data->birthday.day=-1;
data->birthday.month=-1;
data->birthday.year=-1;
}
// Remove the data from a person
void person_free(tPerson* data) {
// Check input data
assert(data != NULL);
// Release document data
if(data->document != NULL) free(data->document);
data->document = NULL;
// Release name data
if(data->name != NULL) free(data->name);
data->name = NULL;
// Release surname data
if(data->surname != NULL) free(data->surname);
data->surname = NULL;
// Release email data
if(data->email != NULL) free(data->email);
data->email = NULL;
// Release address data
if(data->address != NULL) free(data->address);
data->address = NULL;
// Release cp data
if(data->cp != NULL) free(data->cp);
data->cp = NULL;
}
// Remove the data from all persons
void population_free(tPopulation* data) {
int i;
// Check input data
assert(data != NULL);
// Remove contents
for(i = 0; i < data->count; i++) {
person_free(&(data->elems[i]));
}
// Release memory
if (data->count > 0) {
free(data->elems);
data->elems = NULL;
data->count = 0;
}
}
// Parse input from CSVEntry
void person_parse(tPerson* data, tCSVEntry entry) {
// Check input data
assert(data != NULL);
// Check entry fields
assert(csv_numFields(entry) == 7);
// Remove old data
person_free(data);
// Copy identity document data
data->document = (char*) malloc((strlen(entry.fields[0]) + 1) * sizeof(char));
assert(data->document != NULL);
memset(data->document, 0, (strlen(entry.fields[0]) + 1) * sizeof(char));
csv_getAsString(entry, 0, data->document, strlen(entry.fields[0]) + 1);
// Copy name data
data->name = (char*) malloc((strlen(entry.fields[1]) + 1) * sizeof(char));
assert(data->name != NULL);
memset(data->name, 0, (strlen(entry.fields[1]) + 1) * sizeof(char));
csv_getAsString(entry, 1, data->name, strlen(entry.fields[1]) + 1);
// Copy surname data
data->surname = (char*) malloc((strlen(entry.fields[2]) + 1) * sizeof(char));
assert(data->surname != NULL);
memset(data->surname, 0, (strlen(entry.fields[2]) + 1) * sizeof(char));
csv_getAsString(entry, 2, data->surname, strlen(entry.fields[2]) + 1);
// Copy email data
data->email = (char*) malloc((strlen(entry.fields[3]) + 1) * sizeof(char));
assert(data->email != NULL);
memset(data->email, 0, (strlen(entry.fields[3]) + 1) * sizeof(char));
csv_getAsString(entry, 3, data->email, strlen(entry.fields[3]) + 1);
// Copy address data
data->address = (char*) malloc((strlen(entry.fields[4]) + 1) * sizeof(char));
assert(data->address != NULL);
memset(data->address, 0, (strlen(entry.fields[4]) + 1) * sizeof(char));
csv_getAsString(entry, 4, data->address, strlen(entry.fields[4]) + 1);
// Copy cp data
data->cp = (char*) malloc((strlen(entry.fields[5]) + 1) * sizeof(char));
assert(data->cp != NULL);
memset(data->cp, 0, (strlen(entry.fields[5]) + 1) * sizeof(char));
csv_getAsString(entry, 5, data->cp, strlen(entry.fields[5]) + 1);
// Check birthday lenght
assert(strlen(entry.fields[6]) == 10);
// Parse the birthday date
sscanf(entry.fields[6], "%d/%d/%d", &(data->birthday.day), &(data->birthday.month), &(data->birthday.year));
}
// Add a new person
void population_add(tPopulation* data, tPerson person) {
// Check input data
assert(data != NULL);
// If person does not exist add it
if(population_find(data[0], person.document) < 0) {
// Allocate memory for new element
if (data->count == 0) {
// Request new memory space
data->elems = (tPerson*) malloc(sizeof(tPerson));
} else {
// Modify currently allocated memory
data->elems = (tPerson*) realloc(data->elems, (data->count + 1) * sizeof(tPerson));
}
assert(data->elems != NULL);
// Initialize the new element
person_init(&(data->elems[data->count]));
// Copy the data to the new position
person_cpy(&(data->elems[data->count]), person);
// Increase the number of elements
data->count ++;
}
}
// Remove a person
void population_del(tPopulation* data, const char *document) {
int i;
int pos;
// Check input data
assert(data != NULL);
// Find if it exists
pos = population_find(data[0], document);
if (pos >= 0) {
// Remove current position memory
person_free(&(data->elems[pos]));
// Shift elements
for(i = pos; i < data->count-1; i++) {
// Copy address of element on position i+1 to position i
data->elems[i] = data->elems[i+1];
}
// Update the number of elements
data->count--;
// Resize the used memory
if (data->count == 0) {
// No element remaining
free(data->elems);
data->elems = NULL;
} else {
// Still some elements are remaining
data->elems = (tPerson*)realloc(data->elems, data->count * sizeof(tPerson));
}
}
}
// Return the position of a person with provided document. -1 if it does not exist
int population_find(tPopulation data, const char* document) {
int i;
for(i = 0; i < data.count; i++) {
if(strcmp(data.elems[i].document, document) == 0 ) {
return i;
}
}
return -1;
}
// Print the person data
void population_print(tPopulation data) {
int i;
for(i = 0; i < data.count; i++) {
// Print position and document
printf("%d;%s;", i, data.elems[i].document);
// Print name and surname
printf("%s;%s;", data.elems[i].name, data.elems[i].surname);
// Print email
printf("%s;", data.elems[i].email);
// Print address and CP
printf("%s;%s;", data.elems[i].address, data.elems[i].cp);
// Print birthday date
printf("%02d/%02d/%04d\n", data.elems[i].birthday.day, data.elems[i].birthday.month, data.elems[i].birthday.year);
}
}
// Copy the data from the source to destination
void person_cpy(tPerson* destination, tPerson source) {
// Remove old data
person_free(destination);
// Copy identity document data
destination->document = (char*) malloc((strlen(source.document) + 1) * sizeof(char));
assert(destination->document != NULL);
strcpy(destination->document, source.document);
// Copy name data
destination->name = (char*) malloc((strlen(source.name) + 1) * sizeof(char));
assert(destination->name != NULL);
strcpy(destination->name, source.name);
// Copy surname data
destination->surname = (char*) malloc((strlen(source.surname) + 1) * sizeof(char));
assert(destination->surname != NULL);
strcpy(destination->surname, source.surname);
// Copy email data
destination->email = (char*) malloc((strlen(source.email) + 1) * sizeof(char));
assert(destination->email != NULL);
strcpy(destination->email, source.email);
// Copy address data
destination->address = (char*) malloc((strlen(source.address) + 1) * sizeof(char));
assert(destination->address != NULL);
strcpy(destination->address, source.address);
// Copy cp data
destination->cp = (char*) malloc((strlen(source.cp) + 1) * sizeof(char));
assert(destination->cp != NULL);
strcpy(destination->cp, source.cp);
// Copy the birthday date
destination->birthday = source.birthday;
}
// Return population lenght
int population_len(tPopulation data) {
return data.count;
}

View file

@ -0,0 +1,346 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "vaccine.h"
// Initialize vaccine structure
void vaccine_init(tVaccine* vaccine, const char* name, int required, int days) {
assert(vaccine != NULL);
assert(name != NULL);
// Allocate memory for the name
vaccine->name = (char*) malloc(strlen(name) + 1);
assert(vaccine->name != NULL);
// Set the data
strcpy(vaccine->name, name);
vaccine->required = required;
vaccine->days = days;
}
// Release vaccine data
void vaccine_free(tVaccine* vaccine) {
assert(vaccine != NULL);
// Release used memory
if (vaccine->name != NULL) {
free(vaccine->name);
vaccine->name = NULL;
}
}
// Copy the data of a vaccine from the source to destination
void vaccine_cpy(tVaccine* destination, tVaccine source) {
assert(destination != NULL);
// Set the data
vaccine_init(destination, source.name, source.required, source.days);
}
// Release vaccine lot data
void vaccineLot_init(tVaccineLot* lot, tVaccine* vaccine, const char* cp, tDateTime timestamp, int doses) {
assert(lot != NULL);
assert(cp != NULL);
// Allocate memory for the cp
lot->cp = (char*) malloc(strlen(cp) + 1);
assert(lot->cp != NULL);
// Set the data
strcpy(lot->cp, cp);
lot->vaccine = vaccine;
lot->timestamp = timestamp;
lot->doses = doses;
}
// Release vaccine lot data
void vaccineLot_free(tVaccineLot* lot) {
assert(lot != NULL);
// Release used memory
if (lot->cp != NULL) {
free(lot->cp);
lot->cp = NULL;
}
}
// Copy the data of a vaccine lot from the source to destination
void vaccineLot_cpy(tVaccineLot* destination, tVaccineLot source) {
assert(destination != NULL);
// Set the data
vaccineLot_init(destination, source.vaccine, source.cp, source.timestamp, source.doses);
}
// Parse input from CSVEntry
void vaccineLot_parse(tVaccine* vaccine, tVaccineLot* lot, tCSVEntry entry) {
char date[11];
char time[6];
char buffer[512];
tDateTime timestamp;
int doses;
int required;
int days;
// Check input data
assert(vaccine != NULL);
assert(lot != NULL);
assert(csv_numFields(entry) == 7);
// Get Lot data
csv_getAsString(entry, 0, date, 11);
csv_getAsString(entry, 1, time, 6);
dateTime_parse(&timestamp, date, time);
csv_getAsString(entry, 2, buffer, 511);
doses = csv_getAsInteger(entry, 6);
// Initialize the lot structure
vaccineLot_init(lot, NULL, buffer, timestamp, doses);
// Get vaccine data
csv_getAsString(entry, 3, buffer, 511);
required = csv_getAsInteger(entry, 4);
days = csv_getAsInteger(entry, 5);
// Initialize the vaccine data
vaccine_init(vaccine, buffer, required, days);
}
// Initialize the vaccine's list
void vaccineList_init(tVaccineList* list) {
assert(list != NULL);
list->first = NULL;
list->count = 0;
}
// Remove all elements
void vaccineList_free(tVaccineList* list) {
tVaccineNode *pNode = NULL;
tVaccineNode *pAux = NULL;
assert(list != NULL);
pNode = list->first;
while(pNode != NULL) {
// Store the position of the current node
pAux = pNode;
// Move to the next node in the list
pNode = pNode->next;
// Remove previous node
vaccine_free(&(pAux->vaccine));
free(pAux);
}
// Initialize to an empty list
vaccineList_init(list);
}
// Get the number of vaccines
int vaccineList_len(tVaccineList list) {
return list.count;
}
// Find a vaccine in the list of vaccines
tVaccine* vaccineList_find(tVaccineList list, const char* name) {
tVaccineNode *pNode = NULL;
tVaccineNode *pVaccine = NULL;
// Point the first element
pNode = list.first;
while(pNode != NULL && pVaccine == NULL) {
// Compare current node with given name
if (strcmp(pNode->vaccine.name, name) == 0) {
pVaccine = pNode;
}
pNode = pNode->next;
}
return &(pVaccine->vaccine);
}
// Add a new vaccine
void vaccineList_insert(tVaccineList* list, tVaccine vaccine) {
tVaccineNode *pNode = NULL;
tVaccineNode *pPrev = NULL;
assert(list != NULL);
// If the list is empty add the node as first position
if (list->count == 0) {
list->first = (tVaccineNode*) malloc(sizeof(tVaccineNode));
list->first->next = NULL;
vaccine_cpy(&(list->first->vaccine), vaccine);
} else {
// Point the first element
pNode = list->first;
pPrev = pNode;
// Advance in the list up to the insertion point or the end of the list
while(pNode != NULL && strcmp(pNode->vaccine.name, vaccine.name) < 0) {
pPrev = pNode;
pNode = pNode->next;
}
if (pNode == pPrev) {
// Insert as first element
list->first = (tVaccineNode*) malloc(sizeof(tVaccineNode));
list->first->next = pNode;
vaccine_cpy(&(list->first->vaccine), vaccine);
} else {
// Insert after pPrev
pPrev->next = (tVaccineNode*) malloc(sizeof(tVaccineNode));
vaccine_cpy(&(pPrev->next->vaccine), vaccine);
pPrev->next->next = pNode;
}
}
list->count ++;
}
// Remove a vaccine
void vaccineList_del(tVaccineList* list, const char* vaccine) {
tVaccineNode *pNode = NULL;
tVaccineNode *pPrev = NULL;
assert(list != NULL);
// Check if the list has elements
if (list->count > 0) {
pNode = list->first;
// Check if we are removing the first position
if (strcmp(pNode->vaccine.name, vaccine) == 0) {
list->first = pNode->next;
} else {
// Search in the list
pPrev = pNode;
while (pNode != NULL) {
if (strcmp(pNode->vaccine.name, vaccine) == 0) {
// Link previous and next nodes
pPrev->next = pNode->next;
// Remove node
vaccine_free(&(pNode->vaccine));
free(pNode);
list->count ++;
pNode = NULL;
} else {
pPrev = pNode;
pNode = pNode->next;
}
}
}
}
}
// Initialize the vaccine lots data
void vaccineLotData_init(tVaccineLotData* data) {
assert(data != NULL);
// Set the initial number of elements to zero.
data->count = 0;
data->elems = NULL;
}
// Remove all elements
void vaccineLotData_free(tVaccineLotData* data) {
int i;
if (data->elems != NULL) {
for(i=0; i < data->count; i++) {
vaccineLot_free(&(data->elems[i]));
}
free(data->elems);
}
vaccineLotData_init(data);
}
// Get the number of lots
int vaccineLotData_len(tVaccineLotData data) {
// Return the number of lots
return data.count;
}
// Add a new vaccine lot
void vaccineLotData_add(tVaccineLotData* data, tVaccineLot lot) {
int idx = -1;
// Check input data (Pre-conditions)
assert(data != NULL);
// Check if an entry with this data already exists
idx = vaccineLotData_find(*data, lot.cp, lot.vaccine->name, lot.timestamp);
// If it does not exist, create a new entry, otherwise add the number of doses
if (idx < 0) {
if (data->elems == NULL) {
data->elems = (tVaccineLot*) malloc(sizeof(tVaccineLot));
} else {
data->elems = (tVaccineLot*) realloc(data->elems, (data->count + 1) * sizeof(tVaccineLot));
}
assert(data->elems != NULL);
vaccineLot_cpy(&(data->elems[data->count]), lot);
data->count ++;
} else {
data->elems[idx].doses += lot.doses;
}
}
// Remove vaccines from a lot
void vaccineLotData_del(tVaccineLotData* data, const char* cp, const char* vaccine, tDateTime timestamp, int doses) {
int idx;
int i;
assert(cp != NULL);
assert(vaccine != NULL);
// Check if an entry with this data already exists
idx = vaccineLotData_find(*data, cp, vaccine, timestamp);
if (idx >= 0) {
// Reduce the number of doses
data->elems[idx].doses -= doses;
// Shift elements to remove selected
if (data->elems[idx].doses <= 0) {
for(i = idx; i < data->count-1; i++) {
// Remove the data from this position
vaccineLot_free(&(data->elems[i]));
// Copy element on position i+1 to position i
vaccineLot_cpy(&(data->elems[i]), data->elems[i+1]);
}
// Update the number of elements
data->count--;
// Free last position
vaccineLot_free(&(data->elems[data->count]));
}
if (data->count > 0) {
data->elems = (tVaccineLot*) realloc(data->elems, data->count * sizeof(tVaccineLot));
assert(data->elems != NULL);
} else {
free(data->elems);
data->elems = NULL;
}
}
}
// Return the position of a vaccine lot entry with provided information. -1 if it does not exist
int vaccineLotData_find(tVaccineLotData data, const char* cp, const char* vaccine, tDateTime timestamp) {
int i;
assert(cp != NULL);
assert(vaccine != NULL);
for(i = 0; i < data.count; i++) {
if(strcmp(data.elems[i].cp, cp) == 0 && strcmp(data.elems[i].vaccine->name, vaccine) == 0 && dateTime_equals(data.elems[i].timestamp, timestamp)) {
return i;
}
}
return -1;
}

48
UOC20212/src/main.c Normal file
View file

@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#include "test_suite.h"
#include "test.h"
int main(int argc, char **argv)
{
tAppArguments parameters;
tTestSuite testSuite;
// Parse input arguments
if (!parseArguments(&parameters, argc, argv)) {
printf("ERROR: Invalid input arguments");
// Wait user to press a key to ensure error is shown
waitKey(parameters);
// Exit with error
exit(EXIT_FAILURE);
}
// Initialize the test suite
testSuite_init(&testSuite);
// Set the progress file
testSuite_set_progress_file(&testSuite, parameters.progress_file);
// Run all tests
testSuite_run(&testSuite, parameters.in_file, parameters.readme_file);
// Print test results
testSuite_print(&testSuite);
// Store test results
if (parameters.out_file != NULL) {
testSuite_export(&testSuite, parameters.out_file);
printf("Restults stored in %s\n", parameters.out_file);
}
if (parameters.progress_file != NULL) {
printf("Progress stored in %s\n", parameters.progress_file);
}
// Remove test suite data
testSuite_free(&testSuite);
// Wait user to press a key to ensure results are shown
waitKey(parameters);
exit(EXIT_SUCCESS);
}

View file

@ -0,0 +1,14 @@
#ifndef __TEST__H
#define __TEST__H
#include "test_suite.h"
// Write data to file
void save_data(const char* filename, const char* data);
// Run all available tests
void testSuite_run(tTestSuite* test_suite, const char* input, const char* readme);
// Check if README.txt is available and have the correct information
//void readReadme(tTestSuite* test_suite);
#endif // __TEST__H

View file

@ -0,0 +1,14 @@
#ifndef __TEST_DATA__H
#define __TEST_DATA__H
// Define test data for PR1
const char* test_data_pr1_str = "PERSON;87654321K;John;Smith;john.smith@example.com;My street, 25;08001;30/12/1980\n" \
"PERSON;98765432J;Jane;Doe;jane.doe@example.com;Her street, 5;08500;12/01/1995\n" \
"VACCINE_LOT;01/01/2022;13:45;08001;PFIZER;2;21;300\n" \
"VACCINE_LOT;01/01/2022;13:45;08500;PFIZER;2;21;300\n" \
"VACCINE_LOT;01/01/2022;13:45;08001;PFIZER;2;21;50\n" \
"VACCINE_LOT;02/01/2022;18:00;08500;MODERNA;1;0;100\n" \
"VACCINE_LOT;02/01/2022;15:45;08001;MODERNA;1;0;100\n" \
"VACCINE_LOT;03/01/2022;13:45;08500;PFIZER;2;21;70\n";
#endif // TEST_DATA__H

View file

@ -0,0 +1,20 @@
#ifndef __TEST_PR1_H__
#define __TEST_PR1_H__
#include <stdbool.h>
#include "test_suite.h"
// Run all tests for PR1
bool run_pr1(tTestSuite* test_suite, const char* input);
// Run tests for PR1 exercice 1
bool run_pr1_ex1(tTestSection* test_section, const char* input);
// Run tests for PR1 exercice 2
bool run_pr1_ex2(tTestSection* test_section, const char* input);
// Run tests for PR1 exercice 3
bool run_pr1_ex3(tTestSection* test_section, const char* input);
#endif // __TEST_PR1_H__

View file

@ -0,0 +1,183 @@
#ifndef __TEST_SUITE__H
#define __TEST_SUITE__H
#include <stdbool.h>
#include <stdbool.h>
#include <stdio.h>
// #define PRINT_TEST_PROGRESS
// Size of the buffer used to read files data
#define BUFFER_SIZE 2048
// Arguments for a test program
typedef struct _AppArguments {
char* app_name;
char* out_file;
char* in_file;
char* readme_file;
char* progress_file;
bool wait_on_exit;
} tAppArguments;
// Status of a test
typedef enum {
TEST_RUNNING,
TEST_NOT_IMPLEMENTED,
TEST_PASSED,
TEST_FAILED
} tTestResult;
// A single test
typedef struct {
// Code of the test
char* code;
// Description of the test
char* description;
// Result of the test
tTestResult result;
} tTest;
// Grup of tests
typedef struct {
// Code of the test section
char* code;
// Title of the section
char* title;
// Number of tests
int numTests;
// Array of tests
tTest* tests;
// Progress file
char* progress_file;
} tTestSection;
// Test suit learner data
typedef struct {
// Email
char* email;
// Username
char* username;
// First name
char* first_name;
// Last name
char* last_name;
// Environment
char* environment;
// Whether the learner data file exists or not
bool file_exists;
} tLearnerData;
// Test suit with multiple sections
typedef struct {
// Learner data
tLearnerData learner;
// Number of sections
int numSections;
// Array of sections
tTestSection* sections;
// Progress file
char* progress_file;
} tTestSuite;
// Wait user key
void waitKey(tAppArguments parameters);
// Display help text
void help(const char* app_name);
// Parse application arguments
bool parseArguments(tAppArguments* arguments, int argc, char **argv);
// Initialize a test Suite
void testSuite_init(tTestSuite* object);
// Set output progress file
void testSuite_set_progress_file(tTestSuite* object, char* progress_file);
// Load learner data
bool testSuite_load_learner(tTestSuite* object, const char* file);
// Remove a test Suite
void testSuite_free(tTestSuite* object);
// Add a test Section
void testSuite_addSection(tTestSuite* object, const char* code, const char* title);
// Add a test
void testSuite_addTest(tTestSuite* object, const char* section_code, const char* code, const char* description, tTestResult result);
// Update a test result
void testSuite_updateTest(tTestSuite* object, const char* section_code, const char* test_code, tTestResult result);
// Get a pointer to a section
tTestSection* testSuite_getSection(tTestSuite* object, const char* section_code);
// Get a pointer to a test
tTest* testSuite_getTest(tTestSuite* object, const char* section_code, const char* test_code);
// Get test statistics
void testSuite_getStats(tTestSuite* object, int* total, int* passed, int* failed, int* not_implemented);
// Print test suite
void testSuite_print(tTestSuite* object);
// Export a test suite
void testSuite_export(tTestSuite* object, const char* output);
// Initialize a test Section
void testSection_init(tTestSection* object, const char* code, const char* title);
// Remove a test Section
void testSection_free(tTestSection* object);
// Add a test to the Section
void testSection_addTest(tTestSection* object, const char* code, const char* description, tTestResult result);
// Update a test result
void testSection_updateTest(tTestSection* object, const char* test_code, tTestResult result);
// Get a pointer to a test
tTest* testSection_getTest(tTestSection* object, const char* test_code);
// Get test statistics
void testSection_getStats(tTestSection* object, int* total, int* passed, int* failed, int* not_implemented);
// Print test section
void testSection_print(tTestSection* object);
// Export a test section
void testSection_export(tTestSection* object, FILE* fout);
// Initialize a test
void test_init(tTest* object, const char* code, const char* description, tTestResult result);
// Remove a test
void test_free(tTest* object);
// Update a test result
void test_updateTest(tTest* object, tTestResult result);
// Print test
void test_print(tTest* object);
// Export a test
void test_export(tTest* object, FILE* fout);
// Start a test
void start_test(tTestSection* section, const char* code, const char* description);
// Finish a test
void end_test(tTestSection* section, const char* code, bool passed);
// Set output progress file
void _save_progress(tTestSection* section, const char* test_code, const char* test_result);
#endif // __TEST_SUITE__H

45
UOC20212/test/src/test.c Normal file
View file

@ -0,0 +1,45 @@
#include <assert.h>
#include <string.h>
#include "test_data.h"
#include "test.h"
#include "test_pr1.h"
// Write data to file
void save_data(const char* filename, const char* data) {
FILE *fout;
fout = fopen(filename, "w");
assert(fout != NULL);
fwrite(data, strlen(data), 1, fout);
fclose(fout);
}
// Run all available tests
void testSuite_run(tTestSuite* test_suite, const char* input, const char* readme) {
const char* default_readme = "../README.txt";
const char* filename;
assert(test_suite != NULL);
// Load the README.txt file
if (readme == NULL) {
testSuite_load_learner(test_suite, default_readme);
} else {
testSuite_load_learner(test_suite, readme);
}
//////////////////////
// Run tests for PR1
//////////////////////
// If no file is provided, use default data for PR1
if (input == NULL) {
filename = "test_data_pr1.csv";
save_data(filename, test_data_pr1_str);
} else {
filename = input;
}
// Run tests
run_pr1(test_suite, filename);
}

View file

@ -0,0 +1,380 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "test_pr1.h"
#include "api.h"
// Run all tests for PR1
bool run_pr1(tTestSuite* test_suite, const char* input) {
bool ok = true;
tTestSection* section = NULL;
assert(test_suite != NULL);
testSuite_addSection(test_suite, "PR1", "Tests for PR1 exercices");
section = testSuite_getSection(test_suite, "PR1");
assert(section != NULL);
ok = run_pr1_ex1(section, input);
ok = run_pr1_ex2(section, input) && ok;
ok = run_pr1_ex3(section, input) && ok;
return ok;
}
// Run all tests for Exercice 1 of PR1
bool run_pr1_ex1(tTestSection* test_section, const char* input) {
bool passed = true, failed = false;
const char* version;
/////////////////////////////
///// PR1 EX1 TEST 1 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX1_1", "Read version information.");
// Get the version
version = api_version();
if (strcmp(version, "UOC PP 20212") != 0) {
failed = true;
passed = false;
}
end_test(test_section, "PR1_EX1_1", !failed);
return passed;
}
// Run all tests for Exercice 2 of PR1
bool run_pr1_ex2(tTestSection* test_section, const char* input) {
tApiData data;
tApiError error;
tCSVEntry entry;
int nLots;
int nVaccines;
int nPeople;
bool passed = true;
bool failed = false;
bool fail_all = false;
/////////////////////////////
///// PR1 EX2 TEST 1 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_1", "Initialize the API data structure");
// Initialize the data
error = api_initData(&data);
if (error != E_SUCCESS) {
failed = true;
passed = false;
fail_all = true;
}
end_test(test_section, "PR1_EX2_1", !failed);
/////////////////////////////
///// PR1 EX2 TEST 2 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_2", "Add a valid lot");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
csv_parseEntry(&entry, "01/01/2022;13:45;08001;PFIZER;2;21;300", "VACCINE_LOT");
error = api_addVaccineLot(&data, entry);
if (error != E_SUCCESS) {
failed = true;
passed = false;
fail_all = true;
}
csv_freeEntry(&entry);
}
end_test(test_section, "PR1_EX2_2", !failed);
/////////////////////////////
///// PR1 EX2 TEST 3 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_3", "Check the number of vaccines");
if (fail_all) {
failed = true;
} else {
nVaccines = api_vaccineCount(data);
if (nVaccines != 1) {
failed = true;
passed = false;
fail_all = true;
}
}
end_test(test_section, "PR1_EX2_3", !failed);
/////////////////////////////
///// PR1 EX2 TEST 4 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_4", "Check the number of vaccine lots");
if (fail_all) {
failed = true;
} else {
nLots = api_vaccineLotsCount(data);
if (nLots != 1) {
failed = true;
passed = false;
fail_all = true;
}
}
end_test(test_section, "PR1_EX2_4", !failed);
/////////////////////////////
///// PR1 EX2 TEST 5 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_5", "Add a lot with invalid type");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
csv_parseEntry(&entry, "01/01/2022;13:45;08001;PFIZER;2;21;300", "VACCINE_LOT_DATA");
error = api_addVaccineLot(&data, entry);
if (error != E_INVALID_ENTRY_TYPE) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
}
end_test(test_section, "PR1_EX2_5", !failed);
/////////////////////////////
///// PR1 EX2 TEST 6 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_6", "Add a lot with invalid fields");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
csv_parseEntry(&entry, "01/01/2022;13:45;08001;PFIZER;2;21;300;extra_field", "VACCINE_LOT");
error = api_addVaccineLot(&data, entry);
if (error != E_INVALID_ENTRY_FORMAT) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
}
end_test(test_section, "PR1_EX2_6", !failed);
/////////////////////////////
///// PR1 EX2 TEST 7 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_7", "Free API data");
if (fail_all) {
failed = true;
} else {
error = api_freeData(&data);
nVaccines = api_vaccineCount(data);
nLots = api_vaccineLotsCount(data);
nPeople = api_populationCount(data);
if (error != E_SUCCESS || nVaccines != 0 || nLots != 0 || nPeople != 0) {
failed = true;
passed = false;
fail_all = true;
}
}
end_test(test_section, "PR1_EX2_7", !failed);
/////////////////////////////
///// PR1 EX2 TEST 8 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX2_8", "Load data from file");
// Load basic data to the API
if (fail_all) {
failed = true;
} else {
error = api_loadData(&data, input, true);
nVaccines = api_vaccineCount(data);
nLots = api_vaccineLotsCount(data);
nPeople = api_populationCount(data);
if (error != E_SUCCESS || nVaccines != 2 || nLots != 5 || nPeople != 2) {
failed = true;
passed = false;
}
}
end_test(test_section, "PR1_EX2_8", !failed);
// Release all data
api_freeData(&data);
return passed;
}
// Run all tests for Exercice 3 of PR1
bool run_pr1_ex3(tTestSection* test_section, const char* input) {
tApiData data;
tApiError error;
tCSVEntry entry;
tCSVEntry refEntry;
tCSVData report;
tCSVData refReport;
tDateTime timestamp;
int nLots;
int nVaccines;
int nPeople;
bool passed = true;
bool failed = false;
bool fail_all = false;
// Initialize the data
error = api_initData(&data);
if (error != E_SUCCESS) {
passed = false;
fail_all = true;
}
if (!fail_all) {
error = api_loadData(&data, input, true);
nVaccines = api_vaccineCount(data);
nLots = api_vaccineLotsCount(data);
nPeople = api_populationCount(data);
if (error != E_SUCCESS || nVaccines != 2 || nLots != 5 || nPeople != 2) {
passed = false;
fail_all = true;
}
}
/////////////////////////////
///// PR1 EX3 TEST 1 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_1", "Request a valid vaccine");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
csv_initEntry(&refEntry);
csv_parseEntry(&refEntry, "PFIZER;2;21", "VACCINE");
error = api_getVaccine(data, "PFIZER", &entry);
if (error != E_SUCCESS || !csv_equalsEntry(entry, refEntry)) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
csv_freeEntry(&refEntry);
}
end_test(test_section, "PR1_EX3_1", !failed);
/////////////////////////////
///// PR1 EX3 TEST 2 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_2", "Request a missing vaccine");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
error = api_getVaccine(data, "NO_VACC", &entry);
if (error != E_VACCINE_NOT_FOUND) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
}
end_test(test_section, "PR1_EX3_2", !failed);
/////////////////////////////
///// PR1 EX3 TEST 3 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_3", "Request a valid vaccine lot");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
csv_initEntry(&refEntry);
csv_parseEntry(&refEntry, "01/01/2022;13:45;08001;PFIZER;2;21;350", "VACCINE_LOT");
dateTime_parse(&timestamp, "01/01/2022", "13:45");
error = api_getVaccineLot(data, "08001", "PFIZER", timestamp, &entry);
if (error != E_SUCCESS || !csv_equalsEntry(entry, refEntry)) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
csv_freeEntry(&refEntry);
}
end_test(test_section, "PR1_EX3_3", !failed);
/////////////////////////////
///// PR1 EX3 TEST 4 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_4", "Request a missing vaccine lot");
if (fail_all) {
failed = true;
} else {
csv_initEntry(&entry);
dateTime_parse(&timestamp, "01/01/2022", "13:45");
error = api_getVaccineLot(data, "10001", "NO_VACC", timestamp, &entry);
if (error != E_LOT_NOT_FOUND) {
failed = true;
passed = false;
}
csv_freeEntry(&entry);
}
end_test(test_section, "PR1_EX3_4", !failed);
/////////////////////////////
///// PR1 EX3 TEST 5 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_5", "Get registered vaccines");
if (fail_all) {
failed = true;
} else {
csv_init(&report);
csv_init(&refReport);
csv_addStrEntry(&refReport, "MODERNA;1;0", "VACCINE");
csv_addStrEntry(&refReport, "PFIZER;2;21", "VACCINE");
error = api_getVaccines(data, &report);
if (error != E_SUCCESS || !csv_equals(report, refReport)) {
failed = true;
passed = false;
}
csv_free(&report);
csv_free(&refReport);
}
end_test(test_section, "PR1_EX3_5", !failed);
/////////////////////////////
///// PR1 EX3 TEST 6 //////
/////////////////////////////
failed = false;
start_test(test_section, "PR1_EX3_6", "Get registered vaccine lots");
if (fail_all) {
failed = true;
} else {
csv_init(&report);
csv_init(&refReport);
csv_addStrEntry(&refReport, "01/01/2022;13:45;08001;PFIZER;2;21;350", "VACCINE_LOT");
csv_addStrEntry(&refReport, "01/01/2022;13:45;08500;PFIZER;2;21;300", "VACCINE_LOT");
csv_addStrEntry(&refReport, "02/01/2022;18:00;08500;MODERNA;1;0;100", "VACCINE_LOT");
csv_addStrEntry(&refReport, "02/01/2022;15:45;08001;MODERNA;1;0;100", "VACCINE_LOT");
csv_addStrEntry(&refReport, "03/01/2022;13:45;08500;PFIZER;2;21;70", "VACCINE_LOT");
error = api_getVaccineLots(data, &report);
if (error != E_SUCCESS || !csv_equals(report, refReport)) {
failed = true;
passed = false;
}
csv_free(&report);
csv_free(&refReport);
}
end_test(test_section, "PR1_EX3_6", !failed);
// Release all data
api_freeData(&data);
return passed;
}

View file

@ -0,0 +1,674 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "test_suite.h"
// Wait user key
void waitKey(tAppArguments parameters) {
if (parameters.wait_on_exit) {
printf("Press key to continue...");
getchar();
}
}
// Display help text
void help(const char* app_name) {
printf("%s [--help] [--in <input_test_file>] [--out <output_file>] [--progress <progress_file>] [--readme <readme_file>]\n", app_name);
printf("\t[%s] %s\n", "--help", "Show this help information.");
printf("\t[%s] %s\n", "--no-wait", "Do not wait user key press on exit.");
printf("\t[%s] %s\n", "--in", "Provide file with input test data in CSV format.");
printf("\t[%s] %s\n", "--out", "Write the result of tests in a file in JSON format.");
printf("\t[%s] %s\n", "--progress", "Write test progress in an output file.");
printf("\t[%s] %s\n", "--readme", "Path to README.txt file.");
}
// Parse application arguments
bool parseArguments(tAppArguments* arguments, int argc, char **argv) {
int i;
// Initialize the arguments
arguments->app_name = NULL;
arguments->out_file = NULL;
arguments->in_file = NULL;
arguments->readme_file = NULL;
arguments->progress_file = NULL;
arguments->wait_on_exit = true;
// Parse input arguments
arguments->app_name = argv[0];
for (i=1; i < argc; i ++) {
if (strcmp(argv[i], "--help") == 0) {
help(argv[0]);
}
if (strcmp(argv[i], "--no-wait") == 0) {
arguments->wait_on_exit = false;
}
if (strcmp(argv[i], "--in") == 0) {
if (argc < i + 1) {
help(argv[0]);
return false;
}
arguments->in_file = argv[i+1];
i++;
}
if (strcmp(argv[i], "--out") == 0) {
if (argc < i + 1) {
help(argv[0]);
return false;
}
arguments->out_file = argv[i+1];
i++;
}
if (strcmp(argv[i], "--progress") == 0) {
if (argc < i + 1) {
help(argv[0]);
return false;
}
arguments->progress_file = argv[i+1];
i++;
}
if (strcmp(argv[i], "--readme") == 0) {
if (argc < i + 1) {
help(argv[0]);
return false;
}
arguments->readme_file = argv[i+1];
i++;
}
}
return true;
}
// Initialize a test Suite
void testSuite_init(tTestSuite* object) {
assert(object != NULL);
object->learner.email = NULL;
object->learner.username = NULL;
object->learner.first_name = NULL;
object->learner.last_name = NULL;
object->learner.environment = NULL;
object->learner.file_exists = false;
object->numSections = 0;
object->sections = NULL;
object->progress_file = NULL;
}
// Set output progress file
void testSuite_set_progress_file(tTestSuite* object, char* progress_file) {
object->progress_file = progress_file;
}
// Load learner data
bool testSuite_load_learner(tTestSuite* object, const char* file) {
char buffer[BUFFER_SIZE];
FILE *fin=NULL;
int state;
char* pos;
assert(object != NULL);
assert(file != NULL);
fin = fopen(file, "r");
if (fin == NULL) {
object->learner.email = NULL;
object->learner.username = NULL;
object->learner.first_name = NULL;
object->learner.last_name = NULL;
object->learner.environment = NULL;
object->learner.file_exists = false;
return false;
}
state = 0;
while (fgets(buffer, BUFFER_SIZE, fin)) {
if (state == 0) {
// Read email
object->learner.email = (char*) malloc((strlen(buffer) + 1) * sizeof(char));
memset(object->learner.email, 0, (strlen(buffer) + 1) * sizeof(char));
strncpy(object->learner.email, buffer, strcspn(buffer, "\n\r"));
} else if(state == 1) {
// Read Surname, Name
pos = strchr(buffer, ',');
if (pos > 0) {
// Copy the surnames
object->learner.last_name = (char*) malloc((pos - buffer) * sizeof(char));
memset(object->learner.last_name, 0, (pos - buffer) * sizeof(char));
strncpy(object->learner.last_name, buffer, strcspn(buffer, ",") - 1);
// Skip the comma
pos++;
// Skip initial blank spaces
while (pos < &buffer[BUFFER_SIZE] && *pos==' ') pos++;
// Copy the first name
object->learner.first_name = (char*) malloc((strlen(pos) + 1) * sizeof(char));
memset(object->learner.first_name, 0, (strlen(pos) + 1) * sizeof(char));
strncpy(object->learner.first_name, pos, strcspn(pos, "\n\r"));
} else {
object->learner.first_name = (char*) malloc((strlen(buffer) + 1) * sizeof(char));
memset(object->learner.first_name, 0, (strlen(buffer) + 1) * sizeof(char));
strcpy(object->learner.first_name, buffer);
}
} else if(state == 2) {
object->learner.environment = (char*) malloc((strlen(buffer) + 1) * sizeof(char));
strcpy(object->learner.environment, buffer);
} else if(state > 2) {
object->learner.environment = (char*) realloc(object->learner.environment, (strlen(object->learner.environment) + strlen(buffer) + 1) * sizeof(char));
strcat(object->learner.environment, buffer);
}
state ++;
}
object->learner.file_exists = true;
fclose(fin);
return true;
}
// Remove a test Suite
void testSuite_free(tTestSuite* object) {
int i;
assert(object != NULL);
// Free learner data
if(object->learner.email != NULL) {
free(object->learner.email);
object->learner.email = NULL;
}
if(object->learner.username != NULL) {
free(object->learner.username);
object->learner.username = NULL;
}
if(object->learner.first_name != NULL) {
free(object->learner.first_name);
object->learner.first_name = NULL;
}
if(object->learner.last_name != NULL) {
free(object->learner.last_name);
object->learner.last_name = NULL;
}
if(object->learner.environment != NULL) {
free(object->learner.environment);
object->learner.environment = NULL;
}
object->learner.file_exists = false;
// Free test data
if(object->sections != NULL) {
for(i = 0; i < object->numSections; i++) {
testSection_free(&(object->sections[i]));
}
free(object->sections);
}
object->progress_file=NULL;
}
// Add a test Section
void testSuite_addSection(tTestSuite* object, const char* code, const char* title) {
assert(object != NULL);
object->numSections++;
if(object->sections == NULL) {
object->sections = (tTestSection*)malloc(object->numSections * sizeof(tTestSection));
} else {
object->sections = (tTestSection*)realloc(object->sections, object->numSections * sizeof(tTestSection));
}
assert(object->sections != NULL);
testSection_init(&(object->sections[object->numSections - 1]), code, title);
if (object->progress_file != NULL) {
object->sections[object->numSections - 1].progress_file = object->progress_file;
}
}
// Add a test
void testSuite_addTest(tTestSuite* object, const char* section_code, const char* code, const char* description, tTestResult result) {
tTestSection* section = NULL;
assert(object != NULL);
assert(section_code != NULL);
assert(code != NULL);
assert(description != NULL);
section = testSuite_getSection(object, section_code);
assert(section != NULL);
testSection_addTest(section, code, description, result);
}
// Update a test result
void testSuite_updateTest(tTestSuite* object, const char* section_code, const char* test_code, tTestResult result) {
tTestSection* section = NULL;
assert(object != NULL);
assert(section_code != NULL);
assert(test_code != NULL);
section = testSuite_getSection(object, section_code);
assert(section != NULL);
testSection_updateTest(section, test_code, result);
}
// Get a pointer to a section
tTestSection* testSuite_getSection(tTestSuite* object, const char* section_code) {
int i;
assert(object != NULL);
assert(section_code != NULL);
for(i = 0; i < object->numSections; i++) {
if(strcmp(object->sections[i].code, section_code) == 0) {
return &(object->sections[i]);
}
}
return NULL;
}
// Get a pointer to a test
tTest* testSuite_getTest(tTestSuite* object, const char* section_code, const char* test_code) {
tTestSection* section = NULL;
assert(object != NULL);
assert(section_code != NULL);
assert(test_code != NULL);
section = testSuite_getSection(object, section_code);
assert(section != NULL);
if(section != NULL) {
return testSection_getTest(section, test_code);
}
return NULL;
}
// Get test statistics
void testSuite_getStats(tTestSuite* object, int* total, int* passed, int* failed, int* not_implemented) {
int i;
int s_total, s_passed, s_failed, s_not_implemented;
assert(object != NULL);
assert(total != NULL);
assert(passed != NULL);
assert(failed != NULL);
assert(not_implemented != NULL);
*total = 0;
*passed = 0;
*failed = 0;
*not_implemented = 0;
for(i = 0; i < object->numSections; i++) {
testSection_getStats(&(object->sections[i]), &s_total, &s_passed, &s_failed, &s_not_implemented);
*total += s_total;
*passed += s_passed;
*failed += s_failed;
*not_implemented += s_not_implemented;
}
}
// Print test suite
void testSuite_print(tTestSuite* object) {
int i;
int total, passed, failed, not_implemented;
assert(object != NULL);
// Print the header
if (object->learner.file_exists) {
printf("\n=========================================================================\n");
if (object->learner.first_name != NULL && object->learner.last_name != NULL) {
printf("\t Name: %s %s\n", object->learner.first_name, object->learner.last_name);
} else {
printf("\t Name: <not provided>\n");
}
if (object->learner.email != NULL) {
printf("\t Email: %s\n", object->learner.email);
} else {
printf("\t Email: <not provided>\n");
}
printf("=========================================================================\n");
} else {
printf("\n=========================================================================\n");
printf("\t NO LEARNER DATA\n");
printf("=========================================================================\n");
}
testSuite_getStats(object, &total, &passed, &failed, &not_implemented);
printf("\n=========================================================================\n");
printf("\t TEST RESULTS\n");
printf("=========================================================================\n");
if(object->numSections == 0) {
printf("NO TEST DEFINED\n");
} else {
for(i = 0; i < object->numSections; i++) {
testSection_print(&(object->sections[i]));
}
}
printf("\n=========================================================================\n");
if(total > 0) {
printf("Total Tests: %d\n", total);
printf("Passed Tests: %d ( %2.02f %% )\n", passed, ((float)passed / (float)total) * 100.0);
printf("Failed Tests: %d ( %2.02f %% )\n", failed, ((float)failed / (float)total) * 100.0);
//printf("Not Implemented: %d ( %2.02f %% )\n", not_implemented, ((float)not_implemented/(float)total)*100.0);
printf("=========================================================================\n");
}
}
void write_nullable_field(FILE* fout, const char* value) {
if (value == NULL) {
fprintf(fout, "null");
} else {
fprintf(fout, "\"%s\"", value);
}
}
// Export a test suite
void testSuite_export(tTestSuite* object, const char* output) {
int i;
int total, passed, failed, not_implemented;
FILE* fout = NULL;
assert(object != NULL);
assert(output != NULL);
fout = fopen(output, "w");
assert(fout != NULL);
fprintf(fout, "{ \"learner\": {\"first_name\": ");
write_nullable_field(fout, object->learner.first_name);
fprintf(fout, ", \"last_name\": ");
write_nullable_field(fout, object->learner.last_name);
fprintf(fout, ", \"email\": ");
write_nullable_field(fout, object->learner.email);
fprintf(fout, ", \"username\": ");
write_nullable_field(fout, object->learner.username);
fprintf(fout, ", \"environment\": ");
write_nullable_field(fout, object->learner.environment);
fprintf(fout, "}, ");
testSuite_getStats(object, &total, &passed, &failed, &not_implemented);
fprintf(fout, " \"total\": %d, \"passed\": %d, \"failed\": %d, \"not_implemented\": %d, \"sections\": [", total, passed, failed, not_implemented);
for(i = 0; i < object->numSections; i++) {
if(i > 0) {
fprintf(fout, ", ");
}
testSection_export(&(object->sections[i]), fout);
}
fprintf(fout, "]}");
fclose(fout);
}
// Initialize a test Section
void testSection_init(tTestSection* object, const char* code, const char* title) {
assert(object != NULL);
object->code = (char*) malloc((strlen(code) + 1) * sizeof(char));
assert(object->code != NULL);
strcpy(object->code, code);
object->title = (char*) malloc((strlen(title) + 1) * sizeof(char));
assert(object->title != NULL);
strcpy(object->title, title);
object->numTests = 0;
object->tests = NULL;
object->progress_file = NULL;
}
// Remove a test Section
void testSection_free(tTestSection* object) {
int i;
assert(object != NULL);
assert(object->code != NULL);
free(object->code);
free(object->title);
if(object->tests != NULL) {
for(i = 0; i < object->numTests; i++) {
test_free(&(object->tests[i]));
}
free(object->tests);
}
}
// Add a test to the Section
void testSection_addTest(tTestSection* object, const char* code, const char* description, tTestResult result) {
assert(object != NULL);
object->numTests++;
if(object->tests == NULL) {
object->tests = (tTest*)malloc(object->numTests * sizeof(tTest));
} else {
object->tests = (tTest*)realloc(object->tests, object->numTests * sizeof(tTestSection));
}
assert(object->tests != NULL);
test_init(&(object->tests[object->numTests - 1]), code, description, result);
}
// Update a test result
void testSection_updateTest(tTestSection* object, const char* test_code, tTestResult result) {
tTest* test = NULL;
assert(object != NULL);
test = testSection_getTest(object, test_code);
assert(test != NULL);
test_updateTest(test, result);
}
// Get a pointer to a test
tTest* testSection_getTest(tTestSection* object, const char* test_code) {
int i;
assert(object != NULL);
assert(test_code != NULL);
for(i = 0; i < object->numTests; i++) {
if(strcmp(object->tests[i].code, test_code) == 0) {
return &(object->tests[i]);
}
}
return NULL;
}
// Get test statistics
void testSection_getStats(tTestSection* object, int* total, int* passed, int* failed, int* not_implemented) {
int i;
assert(object != NULL);
assert(total != NULL);
assert(passed != NULL);
assert(failed != NULL);
assert(not_implemented != NULL);
*total = object->numTests;
*passed = 0;
*failed = 0;
*not_implemented = 0;
for(i = 0; i < object->numTests; i++) {
if(object->tests[i].result == TEST_PASSED) {
(*passed)++;
} else
if(object->tests[i].result == TEST_FAILED) {
(*failed)++;
} else
if(object->tests[i].result == TEST_FAILED) {
(*not_implemented)++;
}
}
}
// Print test section
void testSection_print(tTestSection* object) {
int i;
int total, passed, failed, not_implemented;
assert(object != NULL);
testSection_getStats(object, &total, &passed, &failed, &not_implemented);
printf("\n\t=================================================================\n");
printf("\t%s\n", object->title);
printf("\t=================================================================\n");
if(object->numTests == 0) {
printf("\tNO TEST DEFINED\n");
} else {
for(i = 0; i < object->numTests; i++) {
test_print(&(object->tests[i]));
}
}
printf("\t=================================================================\n");
if(total > 0) {
printf("\tTotal Tests: %d\n", total);
printf("\tPassed Tests: %d ( %2.2f %% )\n", passed, ((float)passed / (float)total) * 100.0);
printf("\tFailed Tests: %d ( %2.2f %%)\n", failed, ((float)failed / (float)total) * 100.0);
//printf("\tNot Implemented: %d ( %2.2f %%)\n", not_implemented, ((float)not_implemented/(float)total)*100.0);
printf("\t=================================================================\n");
}
}
// Export a test section
void testSection_export(tTestSection* object, FILE* fout) {
int i;
int total, passed, failed, not_implemented;
assert(object != NULL);
assert(fout != NULL);
testSection_getStats(object, &total, &passed, &failed, &not_implemented);
fprintf(fout, "{ \"code\": \"%s\", \"title\": \"%s\", \"total\": %d, \"passed\": %d, \"failed\": %d, \"not_implemented\": %d, \"tests\": [", object->code, object->title, total, passed, failed, not_implemented);
for(i = 0; i < object->numTests; i++) {
if(i > 0) {
fprintf(fout, ", ");
}
test_export(&(object->tests[i]), fout);
}
fprintf(fout, "]}");
}
// Initialize a test
void test_init(tTest* object, const char* code, const char* description, tTestResult result) {
assert(object != NULL);
object->code = (char*) malloc((strlen(code) + 1) * sizeof(char));
assert(object->code != NULL);
object->description = (char*) malloc((strlen(description) + 1) * sizeof(char));
assert(object->description != NULL);
strcpy(object->code, code);
strcpy(object->description, description);
object->result = TEST_RUNNING;
}
// Remove a test
void test_free(tTest* object) {
assert(object != NULL);
assert(object->code != NULL);
assert(object->description != NULL);
free(object->code);
free(object->description);
}
// Update a test result
void test_updateTest(tTest* object, tTestResult result) {
assert(object != NULL);
object->result = result;
}
// Print test
void test_print(tTest* object) {
assert(object != NULL);
printf("\t\t");
if(object->result == TEST_RUNNING) {
printf("[%s]", "RUNNING");
} else
if(object->result == TEST_NOT_IMPLEMENTED) {
printf("[%s]", "NOT IMPLEMENTED");
} else
if(object->result == TEST_PASSED) {
printf("[%s]", "OK");
} else
if(object->result == TEST_FAILED) {
printf("[%s]", "FAIL");
}
printf(":\t [%s] %s\n", object->code, object->description);
}
// Export a test
void test_export(tTest* object, FILE* fout) {
assert(object != NULL);
assert(fout != NULL);
fprintf(fout, "{ \"code\": \"%s\", \"description\": \"%s\", \"result\": ", object->code, object->description);
if(object->result == TEST_RUNNING) {
fprintf(fout, "\"%s\"}", "RUNNING");
} else
if(object->result == TEST_NOT_IMPLEMENTED) {
fprintf(fout, "\"%s\"}", "NOT IMPLEMENTED");
} else
if(object->result == TEST_PASSED) {
fprintf(fout, "\"%s\"}", "OK");
} else
if(object->result == TEST_FAILED) {
fprintf(fout, "\"%s\"}", "FAIL");
}
}
// Start a test
void start_test(tTestSection* section, const char* code, const char* description) {
tTest* test = NULL;
assert(section != NULL);
assert(code != NULL);
assert(description != NULL);
_save_progress(section, code, NULL);
#ifdef PRINT_TEST_PROGRESS
printf("\n[START] ==> Running test [%s] - %s\n", code, description);
#endif // PRINT_TEST_PROGRESS
testSection_addTest(section, code, description, TEST_RUNNING);
test = testSection_getTest(section, code);
assert(test != NULL);
}
// Finish a test
void end_test(tTestSection* section, const char* code, bool passed) {
tTest* test = NULL;
assert(section != NULL);
assert(code != NULL);
test = testSection_getTest(section, code);
assert(test != NULL);
if(passed) {
#ifdef PRINT_TEST_PROGRESS
printf("\n[OK] ==> Finished test [%s] - %s\n", test->code, test->description);
#endif // PRINT_TEST_PROGRESS
_save_progress(section, test->code, "OK");
test_updateTest(test, TEST_PASSED);
} else {
#ifdef PRINT_TEST_PROGRESS
printf("\n[FAIL] ==> Finished test [%s] - %s\n", test->code, test->description);
#endif // PRINT_TEST_PROGRESS
_save_progress(section, test->code, "FAIL");
test_updateTest(test, TEST_FAILED);
}
}
// Set output progress file
void _save_progress(tTestSection* section, const char* test_code, const char* test_result) {
FILE *f_progress=NULL;
if (section->progress_file == NULL) {
return;
}
// Open the file
f_progress = fopen(section->progress_file, "a");
if (f_progress == NULL) {
return;
}
if (test_result == NULL) {
fprintf(f_progress, "TEST:START:{\"section_code\": \"%s\", \"test_code\": \"%s\"}\n", section->code, test_code);
} else {
fprintf(f_progress, "TEST:END:{\"section_code\": \"%s\", \"test_code\": \"%s\", \"result\": \"%s\"}\n", section->code, test_code, test_result);
}
// Close the file
fclose(f_progress);
}