Мне было поручено написать C программное обеспечение для управления библиотекой. Пользователи должны иметь возможность регистрироваться, входить в систему, искать книги, брать и возвращать их и, если они библиотекарь, добавлять и удалять книги из библиотеки. Состояние библиотеки (книги, пользователи, ссуды) должно быть сохранено в файл (я думал о создании для книг и один для пользователей). Я получил book_management.h, который не должен быть изменен, и необходимо написать остальную часть программы а также модульные тесты для функций самостоятельно. У меня были проблемы с тем, что ни одна из функций не могла пройти, хотя я думаю, что мой резонанс в порядке, и я не уверен, что речь идет о реализации моих функций или тестах единства, которые я написал. Буду признателен за любые решения, как это исправить.
Определения из book_management.h
#ifndef BOOK_MANAGEMENT_GUARD__H
#define BOOK_MANAGEMENT_GUARD__H
#include <stdio.h>
struct Book {
char *title; //book title
char *authors; //comma separated list of authors
unsigned int year; // year of publication
unsigned int copies; //number of copies the library has
unsigned int status; //to tell whether it has been borrowed - 1 for borrowed, 0 if in library
};
struct BookArray {
struct Book* array; // pointer to array of struct Book.
unsigned int length; // number of elements in the struct Book * BookArray::find_book_by_author(const char* title)
};
//saves the database of books in the specified file
//returns 0 if books were stored correctly, or an error code otherwise
int store_books(FILE *file);
//loads the database of books from the specified file
//the file must have been generated by a previous call to store_books()
//returns 0 if books were loaded correctly, or an error code otherwise
int load_books(FILE *file);
//adds a book to the ones available to the library
//returns 0 if the book could be added, or an error code otherwise
int add_book (struct Book book);
//removes a book from the library
//returns 0 if the book could be successfully removed, or an error code otherwise.
int remove_book(struct Book book);
//finds books with a given title.
//returns a BookArray structure, where the field "array" is a newly allocated array of books, or null if no book with the
//provided title can be found. The length of the array is also recorded in the returned structure, with 0 in case
//array is the null pointer.
struct BookArray find_book_by_title (const char *title);
//finds books with the given authors.
//returns a BookArray structure, where the field "array" is a newly allocated array of books, or null if no book with the
//provided title can be found. The length of the array is also recorded in the returned structure, with 0 in case
//array is the null pointer.
struct BookArray find_book_by_author (const char *author);
//finds books published in the given year.
//returns a BookArray structure, where the field "array" is a newly allocated array of books, or null if no book with the
//provided title can be found. The length of the array is also recorded in the returned structure, with 0 in case
//array is the null pointer.
struct BookArray find_book_by_year (unsigned int year);
#endif
Определение структуры User от user.h
#define MaxBorrowed 5
struct User {
char* register_name;
unsigned int login; //unique for each
unsigned int status; // librarian (special user) has status 0, others have 1
unsigned int numberBorrowed;
struct Book books_borrowed[MaxBorrowed]; //array of books borrowed by the user
};
//
struct UserArray {
struct User* array; //pointer to an array of struct User
unsigned int length; //length of an array of struct User
};
book_management. ч
#include "book_management.h"
#include "library.h"
#include "books.csv"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxBooksLibrary 1000
struct Book library_books[MaxBooksLibrary];
struct BookArray lib_array;
int store_books(FILE *file) //?
{/*
/* we open the file to write binary
file = fopen("books.bin", "wb");
if (file == 0) {
return -1;
}
int i;
/* write array size */
//fwrite(&(books_in_lib), sizeof(int), 1, file);
/* go through array and write each property of the struct file
for (i = 0; i<books_in_lib(); i++)
{
fwrite(&library_books[i].title, 50 * sizeof(char), 1, file);
fwrite(&library_books[i].authors, 50 * sizeof(char), 1, file);
fwrite(&library_books[i].year, sizeof(int), 1, file);
fwrite(&library_books[i].copies, sizeof(int), 1, file);
fwrite(&library_books[i].status, sizeof(int), 1, file);
}
/*close the file
fclose(file);
return 0;
/*
//open the file
file = fopen("books.bin", "w");
int c;
if( file == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
char data[500];
for (int i=0; i<books_in_lib(); i++)
{
fgets(data, 500, );
fputs(data, file);
}
fclose(file);
return 0;
*/
}
int load_books(FILE *file)
{
char *field;
int i=0;
//open the CSV file
file = fopen("books.csv","r");
if(file == NULL)
{
printf("Unable to open file '%s'\n",file);
exit(1);
}
char characters[400];
// process the data
// the file contains 6 fields in a specific order:
// title,authors,year,copies,status, id
// separated by commas
for (int i=0; i<librarySize; i++)
{
while(fgets(characters,400,file)) //need to write function getline() to jump to the next row while reading the cvs file
{
//get title
field=strtok(characters,",");
library_books[i].title=malloc(strlen(field)+1);
strcpy(library_books[i].title, field);
// get authors
field=strtok(NULL,",");
library_books[i].authors=malloc(strlen(field)+1);
strcpy(library_books[i].authors, field);
// get year
field=strtok(NULL,",");
library_books[i].year=atoi(field);
// get copies
field=strtok(NULL,",");
library_books[i].copies=atoi(field);
// get status
field=strtok(NULL,",");
library_books[i].status=atoi(field);
//i++;
}
}
// close file
fclose(file);
return 0;
*/
}
int add_book (struct Book book)
{
// FILE*f;
//load_books(f);
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].title, NULL)==0 && strcmp(library_books[i].authors, NULL)==0 && library_books[i].year==0 && library_books[i].copies==0 && library_books[i].status==0)
{
strcpy(library_books[books_in_lib()-1].title,book.title);
strcpy(library_books[books_in_lib()-1].authors,book.authors);
library_books[books_in_lib()-1].year=book.year;
library_books[books_in_lib()-1].copies=book.copies;
library_books[books_in_lib()-1].status=book.status;
lib_array.length++;
break; //don't add the book multiple times
}
}
//now go again through library and update info about copies
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].title, book.title)==0 && strcmp(library_books[i].authors,book.authors)==0 )
{
library_books[i].copies++;
}
}
return 0;
}
int remove_book(struct Book book)
{
FILE*f;
load_books(f);
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].title, book.title)==0 && strcmp(library_books[i].authors,book.authors)==0 )
{
book.copies--;
library_books[i].copies--;
library_books[i].title=NULL;
library_books[i].authors= NULL;
library_books[i].year=0;
library_books[i].copies=0;
library_books[i].status=0;
lib_array.length--;
}
}
//now go again through library and update info about copies
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].title, book.title)==0 && strcmp(library_books[i].authors,book.authors)==0)
{
library_books[i].copies--;
}
}
return 0;
}
struct BookArray find_book_by_title (const char *title)
{
struct BookArray foundArray;
struct Book found[MaxBooksLibrary];
int c=0;
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].title,title)==0)
{
strcpy(found[i].title,library_books[i].title);
strcpy(found[i].authors,library_books[i].authors);
found[i].year=library_books[i].year;
found[i].copies=library_books[i].copies;
found[i].status=library_books[i].status;
foundArray.length++;
}
}
foundArray.array=&found[0];
return foundArray;
}
struct BookArray find_book_by_author (const char *author)
{
struct BookArray foundArray;
struct Book found[MaxBooksLibrary];
for (int i=0; i<lib_array.length; i++)
{
if (strcmp(library_books[i].authors,author)==0) //there might have been multiple authors?
{
strcpy(found[i].title,library_books[i].title);
strcpy(found[i].authors,library_books[i].authors);
found[i].year=library_books[i].year;
found[i].copies=library_books[i].copies;
found[i].status=library_books[i].status;
foundArray.length++;
}
}
foundArray.array=&found[0];
return foundArray;
}
struct BookArray find_book_by_year (unsigned int year)
{
struct BookArray foundArray;
struct Book found[MaxBooksLibrary];
for (int i=0; i<lib_array.length; i++)
{
if (library_books[i].year==year)
{
strcpy(found[i].title,library_books[i].title);
strcpy(found[i].authors,library_books[i].authors);
found[i].year=library_books[i].year;
found[i].copies=library_books[i].copies;
found[i].status=library_books[i].status;
foundArray.length++;
}
}
foundArray.array=&found;
return foundArray;
}
int borrow_book(struct User user, struct Book book)
{
/*
for (int i=0; i<lib_array.length; i++)
{
if (strcpy(library_books[i].title,book.title)==0 && user.numberBorrowed<5 && library_books[i].status==0)
{
library_books[i].status=1;
user.books_borrowed[user.numberBorrowed-1]=book;
for (int j=0; j<lib_array.length; j++)
{
if (strcpy(library_books[j].title,book.title)==0)
{
library_books[j].copies--;
}
}
return 0;
}
}
}
int return_book(struct User user, struct Book book)
{
/*
for (j=0; i<MaxBorrowed; j++)
{
if (strcmp(user.books_borrowed[j].title,book.title)==0)
{
strcpy(user.books_borrowed[j].title,NULL)==0 && strcpy(user.books_borrowed[j].authors,NULL)==0 && user.books_borrowed[j].year==0 && user.books_borrowed[j].copies==0 && user.books_borrowed[j].status==0
}
}
for (int i=0; i<lib_array.length; i++)
{
if (library_books[i].id==book.id)
{
library_books[i].status=0;
for (int j=0; j<books_in_lib(); j++)
{
if (strcmp(library_books[j].title,book.title) && strcmp(library_books[j].authors,book.authors) && library_books[j].year==book.year)
{
library_books[j].copies++;
}
}
return 0;
}
}
}
ЕДИНИЦЫ тесты
#include "unity.h"
#include "book_management.h"
#include "users.h"
#include "library.h"
#include <stdio.h>
void test_store_books()
{
FILE* f;
TEST_ASSERT_NOT_NULL_MESSAGE (f, "There's no such file");
TEST_ASSERT_MESSAGE(0==store_books(f), "Books were not stored properly in the file");
}
void test_load_books()
{
FILE* f;
TEST_ASSERT_NOT_NULL_MESSAGE (f, "There's no such file");
TEST_ASSERT_MESSAGE(0==load_books(f), "Books were not loaded properly from the file");
}
void test_add_books()
{
struct Book book ={"Harry Potter", "J.K. Rowling", 1997, 3, 0};
unsigned int prevCopies = book.copies;
TEST_ASSERT_MESSAGE(0==add_book(book), "Book was not added properly to the library");
TEST_ASSERT_MESSAGE(book.copies==prevCopies+1, "Wrong number of books in the library");
}
void test_remove_books()
{
struct Book book = {"Harry Potter", "J.K. Rowling", 1997, 3, 0};
unsigned int prevCopies = book.copies;
TEST_ASSERT_MESSAGE(0==remove_book(book), "Book was not removed properly to the library");
TEST_ASSERT_MESSAGE(book.copies==prevCopies-1, "Wrong number of books in the library");
/
}
void test_find_book_by_title()
{
struct Book book = {"Hobbit", "J.R.R.Tolkien", 1937, 3, 0};
struct BookArray a = find_book_by_title(book.title);
TEST_ASSERT_EQUAL_INT_MESSAGE(3, a.length, "Wrong number of books was found");
}
void test_find_book_by_author()
{
char* author = "J.R.R.Tolkien";
struct Book book1 = {"Hobbit", "J.R.R.Tolkien", 1937, 3, 0};
struct Book book2 = {"Lord of the Rings", "J.R.R.Tolkien", 1954 ,5, 0};
struct Book book3 = {"Silmarillion", "J.R.R.Tolkien", 1977 , 1, 0};
add_book(book1);
add_book(book2);
add_book(book3);
struct BookArray a = find_book_by_author(author);
TEST_ASSERT_EQUAL_INT_MESSAGE(9, a.length, "Wrong number of books was found");
}
void test_find_book_by_year()
{
int year = 1937;
struct Book book1 = {"Hobbit", "J.R.R.Tolkien", 1937, 3, 0};
struct Book book2 = {"Of Mice and Men", "John Steinbeck", 1937, 2, 0};
struct Book book3 = {"Death on the Nile", "Agatha Christie", 1937, 6, 0};
add_book(book1);
add_book(book2);
add_book(book3);
struct BookArray a = find_book_by_year(year);
TEST_ASSERT_EQUAL_INT_MESSAGE(11, a.length, "Wrong number of books was found");
}
void test_store_users()
{
FILE* f;
TEST_ASSERT_MESSAGE(0==store_users(f), "Users's data was not stored properly in the file");
}
void test_load_users()
{
FILE* f;
TEST_ASSERT_MESSAGE(0==load_users(f), "Users' data was not loaded properly from the file");
}
void test_register_new_user()
{
struct User user;
TEST_ASSERT_MESSAGE(0==register_new_user(user), "New user has not been registered properly");
}
void test_log_in()
{
struct User user;
TEST_ASSERT_MESSAGE(0==log_in(user), "New user has not been registered properly");
}
void test_find_user_by_name()
{
struct User u;
TEST_ASSERT_MESSAGE(0!=find_user_by_name(u.register_name), "Function find_user_by_name didn't return a pointer");
}
void test_borrow_book() {
struct Book book= {"Hobbit", "J.R.R.Tolkien", 1937, 3, 0};
struct User user;
user.register_name = "John";
user.login = 232323;
user.status = 0;
user.books_borrowed[MaxBorrowed];
TEST_ASSERT_MESSAGE(0==borrow_book(user, book), "The books hasn't been borrowed");
}
void test_return_book() {
struct Book book= {"Hobbit", "J.R.R.Tolkien", 1937, 3, 0};
struct User user;
user.register_name = "John";
user.login = 232323;
user.status = 0;
user.books_borrowed[MaxBorrowed];
TEST_ASSERT_MESSAGE(0==borrow_book(user, book), "The book has not been returned");
}
void setUp() {
//this function is called before each test, it can be empty
}
void tearDown() {
//this function is called after each test, it can be empty
}
int main() {
UNITY_BEGIN();
RUN_TEST(test_store_books);
RUN_TEST(test_load_books);
RUN_TEST(test_add_books);
RUN_TEST(test_remove_books);
RUN_TEST(test_find_book_by_title);
RUN_TEST(test_find_book_by_author);
RUN_TEST(test_find_book_by_year);
RUN_TEST(test_store_users);
RUN_TEST(test_load_users);
RUN_TEST(test_register_new_user );
RUN_TEST(test_log_in);
RUN_TEST(test_borrow_book);
RUN_TEST(test_return_book);
RUN_TEST(test_find_user_by_name);
return UNITY_END();
}