Initial Commit
This commit is contained in:
commit
5dea15d7a2
24 changed files with 3160 additions and 0 deletions
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal 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
4
UOC20212/README.txt
Normal 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
132
UOC20212/UOC20212.project
Normal 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="<Use Defaults>" DbgSetName="<Use Defaults>">
|
||||||
|
<![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="<Use Defaults>" DbgSetName="<Use Defaults>">
|
||||||
|
<![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>
|
17
UOC20212/UOC20212.workspace
Normal file
17
UOC20212/UOC20212.workspace
Normal 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>
|
116
UOC20212/UOCVaccine/UOCVaccine.project
Normal file
116
UOC20212/UOCVaccine/UOCVaccine.project
Normal 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="<Use Defaults>" DbgSetName="<Use Defaults>">
|
||||||
|
<![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="<Use Defaults>" DbgSetName="<Use Defaults>">
|
||||||
|
<![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>
|
63
UOC20212/UOCVaccine/include/api.h
Normal file
63
UOC20212/UOCVaccine/include/api.h
Normal 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
|
78
UOC20212/UOCVaccine/include/csv.h
Normal file
78
UOC20212/UOCVaccine/include/csv.h
Normal 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
|
31
UOC20212/UOCVaccine/include/date.h
Normal file
31
UOC20212/UOCVaccine/include/date.h
Normal 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__
|
23
UOC20212/UOCVaccine/include/error.h
Normal file
23
UOC20212/UOCVaccine/include/error.h
Normal 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
|
54
UOC20212/UOCVaccine/include/person.h
Normal file
54
UOC20212/UOCVaccine/include/person.h
Normal 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
|
106
UOC20212/UOCVaccine/include/vaccine.h
Normal file
106
UOC20212/UOCVaccine/include/vaccine.h
Normal 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
|
185
UOC20212/UOCVaccine/src/api.c
Normal file
185
UOC20212/UOCVaccine/src/api.c
Normal 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;
|
||||||
|
}
|
265
UOC20212/UOCVaccine/src/csv.c
Normal file
265
UOC20212/UOCVaccine/src/csv.c
Normal 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;
|
||||||
|
}
|
71
UOC20212/UOCVaccine/src/date.c
Normal file
71
UOC20212/UOCVaccine/src/date.c
Normal 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;
|
||||||
|
}
|
272
UOC20212/UOCVaccine/src/person.c
Normal file
272
UOC20212/UOCVaccine/src/person.c
Normal 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;
|
||||||
|
}
|
346
UOC20212/UOCVaccine/src/vaccine.c
Normal file
346
UOC20212/UOCVaccine/src/vaccine.c
Normal 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(×tamp, 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
48
UOC20212/src/main.c
Normal 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(¶meters, 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);
|
||||||
|
}
|
14
UOC20212/test/include/test.h
Normal file
14
UOC20212/test/include/test.h
Normal 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
|
14
UOC20212/test/include/test_data.h
Normal file
14
UOC20212/test/include/test_data.h
Normal 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
|
20
UOC20212/test/include/test_pr1.h
Normal file
20
UOC20212/test/include/test_pr1.h
Normal 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__
|
183
UOC20212/test/include/test_suite.h
Normal file
183
UOC20212/test/include/test_suite.h
Normal 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
45
UOC20212/test/src/test.c
Normal 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);
|
||||||
|
}
|
380
UOC20212/test/src/test_pr1.c
Normal file
380
UOC20212/test/src/test_pr1.c
Normal 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(×tamp, "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(×tamp, "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;
|
||||||
|
}
|
674
UOC20212/test/src/test_suite.c
Normal file
674
UOC20212/test/src/test_suite.c
Normal 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, ¬_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, ¬_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, ¬_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, ¬_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);
|
||||||
|
}
|
Reference in a new issue