Worldstone
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
FileStreamTests.cpp
Go to the documentation of this file.
1 
5 #include <FileStream.h>
6 #include <MpqArchive.h>
7 #include <fstream>
8 #include <string.h>
9 #include "doctest.h"
10 
14 using WorldStone::StreamPtr;
15 
16 namespace
17 {
18 
19 // We are not testing the MpqArchive here, just assume it works for some tests.
20 class MpqFileWrapper : public MpqFileStream
21 {
22  MpqArchive archive;
23 
24 public:
25  MpqFileWrapper(const char* filename) : MpqFileStream(), archive("testArchive.mpq")
26  {
27  REQUIRE_MESSAGE(archive.good(), "This archive should be valid, wrong working directory ?");
28  open(archive, filename);
29  }
30 
31  ~MpqFileWrapper() { close(); }
32 };
33 }
34 typedef doctest::Types<WorldStone::FileStream, MpqFileWrapper> stream_types;
35 
36 TYPE_TO_STRING(WorldStone::FileStream);
37 TYPE_TO_STRING(MpqFileWrapper);
38 
40 SCENARIO_TEMPLATE("Read-only filestreams", StreamType, stream_types)
41 {
42  GIVEN("A file that does not exist")
43  {
44  const char* invalidFileName = "does-not-exist-file";
45  WHEN("Trying to open it")
46  {
47  StreamType stream{invalidFileName};
48  WorldStone::IStream& streamRef = stream; // Test it through the interface
49  THEN("File is not opened and stream is invalid")
50  {
51  REQUIRE_FALSE(stream.is_open()); // Not in IStream, but present for files
52  CHECK_FALSE(streamRef.good());
53  CHECK_FALSE(streamRef.bad());
54  CHECK(streamRef.fail());
55  CHECK_FALSE(streamRef.eof());
56  }
57  // Do not try to call anything else since it causes system API to exit the application.
58  // We do not let the user call read if the file is invalid by design for performance
59  // reasons Note that most calls are guarded by asserts anyway
60  }
61  }
62 
63  GIVEN("A file containing the word \"test\"")
64  {
65  const char* filename = "test.txt";
66  WHEN("Opening the file containing \"test\"")
67  {
68  StreamType stream{filename};
69  WorldStone::IStream& streamRef = stream; // Test it through the interface
70  THEN("File is opened and stream is valid")
71  {
72  REQUIRE(stream.is_open()); // Not in IStream, but present for files
73  CHECK(streamRef.good());
74  CHECK_FALSE(streamRef.bad());
75  CHECK_FALSE(streamRef.fail());
76  CHECK_FALSE(streamRef.eof());
77  CHECK(streamRef.tell() == 0);
78  const size_t fileSize = streamRef.size();
79  const char* fileContent = "test";
80  CHECK(fileSize == strlen(fileContent));
81 
82  AND_WHEN("We read the whole file")
83  {
84  char buffer[256] = {};
85  CHECK(fileSize < 256);
86  streamRef.read(buffer, fileSize);
87  THEN("The buffer contains the same things as the file")
88  {
89  CHECK(!strcmp("test", buffer));
90  CHECK_FALSE(streamRef.eof());
91  CHECK(streamRef.tell() == fileSize);
92  AND_WHEN("We read more")
93  {
94  streamRef.read(buffer, 1);
95  THEN("EOF and fail flags are set")
96  {
97  CHECK(streamRef.eof());
98  CHECK(streamRef.fail());
99  CHECK_FALSE(streamRef.bad());
100  CHECK_FALSE(streamRef.good());
101  }
102  }
103  }
104  }
105  AND_WHEN("We read the whole file using getc")
106  {
107  char buffer[256] = {};
108  CHECK(fileSize < 256);
109  for (size_t i = 0; i < fileSize; i++)
110  {
111  int val = streamRef.getc();
112  CHECK(val >= 0);
113  buffer[i] = static_cast<char>(val);
114  }
115  THEN("The buffer contains the same things as the file")
116  {
117  CHECK(!strcmp("test", buffer));
118  CHECK_FALSE(streamRef.eof());
119  CHECK(streamRef.tell() == fileSize);
120  AND_WHEN("We read more")
121  {
122  int val = streamRef.getc();
123  CHECK(val < 0);
124  THEN("EOF and fail flags are set")
125  {
126  CHECK(streamRef.eof());
127  CHECK(streamRef.fail());
128  CHECK_FALSE(streamRef.bad());
129  CHECK_FALSE(streamRef.good());
130  }
131  }
132  }
133  }
134  AND_WHEN("We read more than the whole file")
135  {
136  char buffer[256] = {};
137  CHECK(fileSize * 2 < 256);
138  size_t readCount = streamRef.read(buffer, fileSize * 2);
139  THEN("EOF is reached and correct number of bytes read is reported")
140  {
141  // We know the content of the file is exactly "test"
142  CHECK(readCount == fileSize);
143  CHECK(strncmp("test", buffer, fileSize) == 0);
144  }
145  }
146  AND_WHEN("You seek past the end of file")
147  {
148  streamRef.seek(10, WorldStone::IStream::end);
149  THEN("There is no failure") // That's the case for fseek since you can start
150  // writing at a given offset
151  {
152  CHECK_FALSE(streamRef.fail());
153  CHECK_FALSE(streamRef.bad());
154  CHECK(streamRef.good());
155  }
156  }
157  AND_WHEN("You seek before the file beginning")
158  {
159  streamRef.seek(-1, WorldStone::IStream::beg);
160  THEN("Fail flag is set") { CHECK(streamRef.fail()); }
161  }
162  }
163  }
164  }
165 }
An interface for a stream of data.
Definition: Stream.h:22
virtual long size()=0
Compute the size of the file.
bool eof() const
True if the end of the stream was reached during the last read operation.
Definition: Stream.h:26
A wrapper to manage MPQ archives.
Definition: MpqArchive.h:17
virtual long tell()=0
Return the current position of the stream pointer.
virtual bool seek(long offset, seekdir origin)=0
Change the pointer of the stream to a given position.
virtual size_t read(void *buffer, size_t size)=0
Read data from the stream.
A file from a MpqArchive.
Definition: MpqArchive.h:47
virtual int getc()
Read one byte from the stream.
Definition: _VTablesTU.cpp:17
Wrapper around POSIX file io, same as ifstream but without iostream formatting.
Definition: FileStream.h:16
SCENARIO_TEMPLATE("Read-only filestreams", StreamType, stream_types)