ECS 034: Software Development in UNIX & C++ - Project 2: CDSVReader and CDSVWriter
ECS34 WQ25
Project 2
You will be working with a partner for this project. This specification is subject to change at any time for additional clarification.
Desired Outcomes
-
● Exposure to GoogleTest
-
● Exposure to Expat XML library
-
● Use of git repository
-
● Exposure to documenting code in Markdown
-
● An understanding of how to develop Makefiles that build and execute unit tests
-
● An understanding of delimiter-separated-value files
-
● An understanding of XML files
-
● An understanding of how to integrate a third-party C library in C++
Project Description
You will be implementing and documenting several C++ classes to generate and parse both delimiter-separated-value (DSV) and XML files. To guide your development and to provide exposure to Test Driven Development, you will be developing GoogleTest tests to test your classes. You will also be developing a Makefile to compile and run your tests. You must use good coding practice by developing this project in a git repository. DSV is a way of exchanging information, you can read more here. Some of the most common forms are comma-separated-value (CSV) and tab-separated-value (TSV) files. You will be implementing two classes CDSVReader and CDSVWriter that have simple interfaces for parsing and generating DSV respectively.
// Constructor for DSV reader, src specifies the data source and delimiter // specifies the delimiting character
CDSVReader(std::shared_ptr< CDataSource > src, char delimiter);// Destructor for DSV reader ~CDSVReader();
// Returns true if all rows have been read from the DSV bool End() const;
// Returns true if the row is successfully read, one string will be put in // the row per column
bool ReadRow(std::vector< std::string > &row);bool quoteall = false); // Destructor for DSV writer
~CDSVWriter();
// Returns true if the row is successfully written, one string per column
// should be put in the row vector
bool WriteRow(const std::vector< std::string > &row);
Some nuances to keep in mind when developing the functions.
-
● Values that have either the delimiter, double quote character ‘"’, or newline must be quoted with double quotes.
-
● Double quote characters in the cell must be replaced with two double quotes.
-
● An empty line is a valid row where there are no values.
-
● A double quote specified as a delimiter is interpreted as a comma ‘,’.
You will be implementing two classes CXMLReader and CXMLWriter that have simple interfaces for parsing and generating XML respectively. The SXMLEntity struct is used by
both classes and has been provided. Complete XML parsing is complicated and beyond the scope of a single assignment; therefore, you will be utilizing the Expat library, a commonly used library for parsing XML. To link the Expat library (libexpat) with your project, use the -lexpat as a linker option.
SXMLEntity{
EType DType; // Type of entity start/end/complete element std::string DNameData;
std::vector< TAttribute > DAttributes;}
// returns true if the attribute name is in the DAttributesbool AttributeExists(const std::string &name) const;
// returns the value of the attribute, or empty string if // doesn't exist
std::string AttributeValue(const std::string &name) const;// Sets the attribute name to the value
bool SetAttribute(const std::string &name, const std::string &value);// Constructor for XML reader, src specifies the data source CXMLReader(std::shared_ptr< CDataSource > src);
// Destructor for XML reader ~CXMLReader();
// Returns true if all entities have been read from the XML bool End() const;
// Returns true if the entity is successfully read if skipcdata // is true only element type entities will be returned
bool ReadEntity(SXMLEntity &entity, bool skipcdata = false);Project 2 2 of 6
ECS34 WQ25 February 4, 2025
// Constructor for XML writer, sink specifies the data destination CXMLWriter(std::shared_ptr< CDataSink > sink);
// Destructor for XML writer ~CXMLWriter();
// Outputs all end elements for those that have been started bool Flush();
// Writes out the entity to the output stream bool WriteEntity(const SXMLEntity &entity);
To abstract the data input/output for the DSV and XML classes, two simple abstract classes CDataSource and CDataSink have been provided for input and output respectively. String implementations of CDataSource and CDataSink, CStringDataSource and CStringDataSink respectively have been provided with associated GoogleTest tests.
The Makefile you develop needs to implement the following:
-
● Must create obj directory for object files (if doesn’t exist)
-
● Must create bin directory for binary files (if doesn’t exist)
-
● Must compile cpp files using C++17
-
● Must link string utils and string utils tests object files to make teststrutils
executable
-
● Must link StringDataSource and StringDataSourceTest object files to make
teststrdatasource executable
-
● Must link StringDataSink and StringDataSinkTest object files to make
teststrdatasink executable
-
● Must link DSV reader/writer and DSV tests object files to make testdsv executable
-
● Must link XML reader/writer and XML tests object files to make testxml executable
-
● Must execute the teststrutils, teststrdatasource, teststrdatasink,
testdsv, and testxml executables
-
● Must provide a clean that will remove the obj and bin directories
You must have a docs directory that contains Markdown (.md) files that document the CDSVReader, CDSVWriter, CXMLReader, and CXMLWriter classes and their use. The documentation of each class and function should be consistent. Code examples are excellent for documenting the use of the developed classes.
You can unzip the given zip file with utilities on your local machine, or if you upload the file to the CSIF, you can unzip it with the command:
unzip proj2given.zipYou must submit the source file(s), your Makefile, README.md file, and.git directory in a zip archive. Do a make clean prior to zipping up your files so the size will be smaller. You
can zip a directory with the command:
zip -r archive-name.zip directory-name
Project 2 3 of 6
ECS34 WQ25 February 4, 2025
You should avoid using existing source code as a primer that is currently available on the Internet. You MUST specify in your README.md file any sources of code that you have viewed to help you complete this project. You MUST properly document ALL uses of Generative AI following the guidelines outlined in the Generative AI Restrictions. All class projects will be submitted to MOSS to determine if students have excessively collaborated. Excessive collaboration, or failure to list external code sources will result in the matter being referred to Student Judicial Affairs.
Recommended Approach
The recommended approach is as follows:
-
Create a git repository and add your project 1 and provided files.
-
Update your project 1 Makefile to meet the specified requirements. The order of the tests
to be run should be teststrutils, teststrdatasource, teststrdatasink,
testdsv, and then testxml
-
Verify that your string utils, string data source, and string data sink tests all compile, run
and pass.
-
Create the docs directory, and begin documenting the classes and functions.
-
Create the files and skeleton functions for DSVReader.cpp, DSVWriter.cpp,
XMLReader.cpp, XMLWriter.cpp, DSVTest.cpp, and XMLTest.cpp.
-
Write tests for the DSV and XML classes. Each test you write should fail, make sure to
have sufficient coverage of the possible input parameters.
-
Once tests have been written that fail with the initial skeleton functions, begin writing
your DSV functions. You may want to start with the writer, this may allow the use of the
writer in testing the reader.
-
Once the DSV classes are complete, begin writing your XML functions. Like the DSV
functions, you may want to start with the writer, this may allow the use of the writer in testing the reader.
Grading
Make sure your code compiles on Gradescope and passes all the test cases.
Helpful Hints
-
● Read through the guides that are provided on Canvas
-
● See http://www.cplusplus.com/reference/, it is a good reference for C++ built in functions
and classes
-
● Use length(), substr(), etc. from the string class whenever possible.
-
● If the build fails, there will likely be errors, scroll back up to the first error and start from
there.
-
● You may find the following line helpful for debugging your code:
std::cout<<__FILE__<<" @ line: "<<__LINE__<<std::endl;
It will output the line string "FILE @ line: X" where FILE is the source filename and X is the line number the code is on. You can copy and paste it in multiple places, and it will output that particular line number when it is on it.Project 2 4 of 6
ECS34 WQ25 February 4, 2025
-
● Make sure to use a tab and not spaces with the Makefile commands for the target
-
● make will not warn about undefined variables by default, you may find the
--warn-undefined-variables option very helpful
-
● The debug option for make can clarify which targets need to be built, and which are not.
The basic debugging can be turned on with the --debug=b option. All debugging can
be turned on with the --debug=a option.
-
● Make sure to use a.gitignore file to ignore your object files, and output binaries.
-
● Do not wait until the end to merge with your partner. You should merge your work
together on a somewhat regular basis (or better yet pair program).
-
● Use CStringDataSource and CStringDataSink to test your reader and writer
classes for DSV and XML.
-
● You will probably want to use static functions in your classes for the callbacks to the
library calls that require callbacks. The call data (void *) parameter that the functions
take, and the callbacks pass back as a parameter, should be this from your object.
-
● You may find https://www.xml.com/pub/1999/09/expat/index.html helpful for describing the libexpat functions. You are not going to need to use every function in the Expat
library.
Project 2 5 of 6