By Developers, For Developers

Historical errata for Modern C++ Programming with Test-Driven Development

PDF PgPaper PgTypeDescriptionFixed onComments
xvTYPO

Hi,

There is a link provided to one of the author’s websites “agileinaflash.com”

However, the link also contains the ending “.”, so I received a “bad hostname” error when clicking on the link — attempting to open it in FireFox. The URL appears as “agileinaflash.com.” If the period just gets moved over, things should be perfect :)

Take care!

Travis

2013-04-03
4TYPO

Section 2.3, Paragraph 2 says “…Rule #4 seems simple, but
the word “continue” suggests that it builds atop the first three rules…"

The “Rule #4” it alludes to is from the SOUNDEX Algorithm Definition. The author says…
“4. Stop when you have a letter and three digits. Zero-pad if needed.”

It has no “continue” in it.

Thanks!

Travis

2013-04-03
viTYPO

Last paragraph of page vi in the intro:
“How can you preventing these challenges
from derailing your transition effort?”
- preventing should be prevent?

2013-04-11
12TYPO

duplicate:
A number of the examples use third-party, freely-available libraries. Refer to
3rd-Party Libraries
Some of the examples use freely-available third-party libraries.

2013-04-03
1SUGGEST

Great stuff! Hopefully the next edition will include a draft of the “Global Setup” chapter — I’m ready to get rolling but don’t have the environment ready.

2013-04-03Thanks Jon... forthcoming soon if you've not already gotten things set up.
12TYPO

In section 2.5,

“However, taking small steps will increase your spead over time…”

‘spead’ should be ‘speed’.

2013-04-03
16TYPO

End of 2nd paragraph: “naming standard.)” has a spurious closing paren.

2013-04-03
16SUGGEST

Naming conventions for the trailing underscore: why this particular convention?

2013-04-03Thanks Jon for the question! It's a convention I've seen used in a couple places. I detest it no more than any other convention I've used. :-) I don't care for "mWhatever," I don't like leading prefixes, I do like things that stand out visually, and I do think it's valuable to know immediately whether something is a local or a member. I was happy to use Whole Tomato for a while, which has some reasonable ability to show the differences via color, but I don't have that in vim (which is what the book is written using).
16TYPO

At the end of section 2.6, there were two example tests; at the end of section 2.7, a third test ReplacesConsonantsWithAppropriateDigits) appears without discussion.

2013-04-03
32TYPO

This should be just “diacrtics” not “diacriticals” (or it could also be “diacritical marks”).

“Our isVowel() function needs to support vowels with diacriticals.”

2013-04-03
81SUGGEST

This sentence is a bit unclear:
“If you’re worried about nefarious other programmers abusing the relaxed access, don’t.” …. do you mean “dont worry” or “dont relax the access”?

2013-04-03
17TYPO

Para 3: add the word ‘test’ to: “We run the tests, but our new [test] does not pass”

2013-04-04
17SUGGEST

Obviously there are many ways of thinking about what to code as a solution. Harking back to your comments on pages 8-10, the “simplest” thing I could think of to get the test to pass was another hard-coded example:
if(word == “Ab”) {
return “A100”;
}
… before refactoring, of course. Seems as if you’re now taking bigger, not quite so simple, steps than you were discussing very pointedly in the first few pages of the book; therefore it might be worth commenting on this before proceeding.

2013-04-05
42TYPO

Section “Thinking and TDD”, paragraph 2: Change “…TDD cycle, you be able to must answer” to “…TDD cycle, you must be able to answer”.

2013-04-05awesome. It's amazing how defective the brain can get.
72TYPO

in the code snippet, 3rd function should be “std::string createCommand…” instead of “std::createCommand…”

2013-04-04
106SUGGEST

in snippet “c5/2/PlaceDescriptionServiceTest.cpp”:
stringutil::ticToQuote is not necessary. The same can be achieved with raw string literals.


(The ticToQuote() method converts single quotes (tics) to double quotes. That prevents us from having to escape scads of embedded double quotes with backslashes.)

2013-04-03
13SUGGEST

The first time that zeroPad() is introduced, it wasn’t clear to me whether it should go in the public or the private section (later code listings clear the matter up).

2013-04-03
14SUGGEST

2.6 and other parts in the chapter, sometimes when you show an excerpt I’m not sure how I’m supposed to be modifying the code. I.e. when you add:

class SoundexEncoding : public Test {
public:
Soundex soundex_;
};

I wasn’t sure where this had to go as the code listing looked complete, yet didn’t include the Soundex class itself.

2013-04-03
16TYPO

This is in the code listing at 2.7 before it’s introduced:

TEST_F(SoundexEncoding, ReplacesConsonantsWithAppropriateDigits) {

ASSERT_THAT(soundex_.encode(“Ab”), Eq(“A100”));

}

2013-04-03
20TYPO

Was I supposed to put “#include ” beforehand? My code was compiling without it… :S

2013-04-10The extraneous #include of course won't harm things, but it's not good to require it unnecessarily either. \n \nFor now I am marking this as "complete" but I will revisit it in the near future, after this beta drop.
24TYPO

2.10, the first code listing does not match with the following text and code listing.

“TEST_F(SoundexEncoding, CombinesDuplicateEncodings) {
ASSERT_THAT(soundex_.encode(”Abfcgdt“), Eq(”A123"));
}

Hm? That’s a confusing test! To understand why Ajcdl encodes to A234, we have to understand that j and c both encode to 2."

2013-04-10
27TYPO

Near the bottom of the page: “A bit of code analysis tells us that encodeDigit() returns null when its map doesn’t contain the requested character. Code in the encodeDigits()”

Should probably be “encodedDigit() / encodedDigits()” since that’s what we called these methods in the code.

2013-04-10I think this chunk of text is gone now
27SUGGEST

Just curious why we need the static_cast in this code:

char upper(const char& c) const {
return static_cast(::toupper©);
}

Maybe a quick sentence or two in the book would help for those on the less experience side? ;)

2013-04-10hmm it might not be necessary. Could've sworn it was causing a warning earlier but maybe not now.
30ERROR

The last changes before 2.12 break the test case “SoundexEncoding.IgnoresVowelLikeLetters”.

2013-04-05Hi Kevin, \n \nI'm looking at c2/32/SoundexTest.cpp. My version passes the tests, although it's possible that there is a bit of code I'm not showing. I'll do a diff and take a further look; you might also send me your code. \n \n(I've run the example several times now, with tweaks each time... I do remember a couple times making a simple mistake on this step, and it taking me a while to find it. Check that the loop starts from 1, the change to IsIncomplete, and the change to encode.) \n \nThanks, \nJeff
12TYPO

“However, taking small steps will increase your spead” <- “speed”

2013-04-03
9TYPO

paragraph 3
Reads: “Google Test prints a [ RUN ] record with each test name when it starts, and a [ FAILED ] or [ PASSED ] bookend when the test fails.”
Problem: Should read something like “Google Test prints a [ RUN ] record with each test name when it starts, and a [ FAILED ] or [ OK ] bookend when the test ends.”

2013-04-03
16ERROR

In program listing, last test ReplacesConsonantsWithAppropriateDigits not mentioned before in text. Remove.

2013-04-03
17SUGGEST

program listing c2/13/SoundexTest.cpp
const std::string head(…
and
const std::string encodedDigits(…

should be

std::string head(…
and
std::string encodedDigits(…

Reason: const-ing the return value does not protect the user for inadvertently changing the result, even with auto. The reader might think so. And it’s less text to read. Plus it’s consistent with encode and zeroPad.

2013-04-03
19SUGGEST

program listing c2/15/SoundexTest.cpp (last)
const std::string encodedDigits(…
should be
std::string encodedDigits(…

for same reason as PDF page 17.

2013-04-03
20SUGGEST

#include is not mentioned before but is used in the “production” code. Now #include is mentioned and #include is already there in code example. Unfortunately, both and are indirectly sourced by <gmock/gmock.h>, thus not needed. I suggest you have and included in the beginning of the file (at appropreate places) followed by the “production” implementation of Soundex, then include <gmock/gmock.h> followed by the test code.

2013-04-10I need to double-check all my usages of #includes, and perhaps order them differently... will take a further look, thanks! \n \nFor now I am marking this as "complete" but I will revisit it in the near future, after this beta drop.
21SUGGEST

const std::string encodedDigits(… , mentioned twice
and
const std::string tail(…

remove const as per motivation on pdf page 17 suggestion.

2013-04-03
22SUGGEST

last listing c2/21/SoundexTest.cpp
I get a compiler warning with gcc 4.7.2:
../SoundexTest.cpp:120:1: required from here
/home/bo/workspace/gmock/include/gmock/gmock-matchers.h:801:1: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

Solved this by changing Eq(4) to Eq(4u).

2013-04-10
64TYPO

On p.64 it says:

“As a reminder of what the test case name is, the following test declaration has a test case name of IncrementsSizeWhenTweetAdded.)
TEST (ARetweetCollection, IncrementsSizeWhenTweetAdded)”

It then says:

“In Google Test, you define a fixture as a class derived from ::testing::Test. You typically define the fixture at the beginning of your test file.
using namespace ::testing;
class ARetweetCollection: public Test {
};”

On page 65 it says:

“The test case name must match the fixture name!”

This implies that the test case name is actually ARetweetCollection? This is a bit confusing.

2013-04-05thanks--the first part was wrong--the "following declaration has a test case name of ARetweetCollection" would be correct.
77TYPO

ASSERT_THAT(actual, ::testing::StartsWith(“al”));

ASSERT_THAT(tweetsAdded, Eq(3));
.. the failure message tells you what the assertion expected plus what was actually received:
Value of: tweetsAdded
Expected: is equal to 3
Actual: 5 (of type unsigned int)
The wording of the failure message is why you always want to specify the expected value as the first argument to the assertion and the actual value (of what you’re verifying) as the second argument.

Given the example before, I think you mean to say you always want to specify the actual value as the first argument and the expected as the second?

2013-04-05
79SUGGEST

TEST (ATweet, RequiresUserNameToStartWithAnAtSign) { string invalidUser(“notStartingWith@”);
try {
Tweet tweet(“msg”, invalidUser);
} catch (const InvalidUserException& expected) {}
}

Is this missing a call to “fail()” after the call to “Tweet tweet(…)” ?

2013-04-10Oops. Good catch. That's what happens when you cheat on red-green-refactor.
12TYPO

“… increase your spead over time …”

2013-04-08
27SUGGEST

c2/27/SoundexTest.cpp regarding the new upper-method

Should have interface “char upper(char c) const”. const reference of chars just causes overhead and is inconsistent with encodedDigit-method.

Also a note on the implementation. Consider
return std::toupper(static_cast©);
and add #include

OR
return ::toupper(static_cast©)
and add #include <ctype.h>

With <ctype.h> you know you have access to ::toupper, but can have access to std::toupper.
With you know you have access to std::toupper, but can have access to ::toupper.

The casting is needed since if c is not an unsigned char value, or EOF, the behavior is undefined. Some locales might have difficulty separating 0xFF from –1 (EOF).

2013-04-10
30SUGGEST

c2/30/SoundexTest.cpp
The change to encodedDigit-method, consider implementing a lower-method and using it instead of ::tolower since we already have upper or cut both upper/lower-methods out for consistency. Whatever you choose, be consistent with the <ctype.h> or include you use as my comment on PDF page 27.

2013-04-10
29SUGGEST

See my remark on PDF page 30. This is were it goes :-)o

2013-04-10Hi Bo and thanks for the great feedback. \nI'm not sure to what this refers, can you clarify? \nThanks! \nAlso-I have to close this today, please create new errata.
30ERROR

To clarify #51202

The code sample is not incorrect, but once you implement the functionality for CombinesDuplicateCodesWhen2ndLetterDuplicates1st it breaks IgnoresVowelLikeLetters. The expected output for IgnoresVowelLikeLetters needs to be updated to “C340”

2013-04-10
31ERROR

Now to follow up on #51256, once you’ve implemented DoesNotCombineDuplicateEncodingsSeparatedByVowels in 2.13 the expected result of IgnoreVowelLikeLetters is once again “C234”

2013-04-10I think "fixed" those by changing earlier tests. Brings up a good but confusing discussion that I would prefer to avoid in this chapter.
79TYPO

“The ASSERT_ANY_THROW macro fails the test if the expression it encloses throws an exception.” - it should fail if the express does not throw an exception

2013-04-11
200ERROR

“Passing a reference would give us a slicing problem”. References are just syntactic sugar for pointers, so you can choose to use either one.

2013-05-06
31ERROR

2.9 Dropping Vowels
When adding TEST_F(SoundexEncoding, IgnoresVowelLikeLetters) the code already in place DOES NOT FAIL. Thus the changes are not motiviated. I checked this with the code in c2/22/SoundexTest.cpp and added the test. It, too, does not fail when adding the test.

2013-05-06hmm. Looking at this now. I guess a bit of rework to a section earlier caused this inconsistency. Good catch, many thanks.
37TYPO

Bottom om page reads:

loop in toDigits() to start at 1, not 0.

should be

loop in encodedDigits() to start at 1, not 0.

2013-05-06
36SUGGEST

Change test TEST_F(SoundexEncoding, IgnoresVowelLikeLetters)
from

ASSERT_THAT(soundex_.encode(“CAaEeIiOoUuHhYycdl”), Eq(“C234”));

to

ASSERT_THAT(soundex_.encode(“BAaEeIiOoUuHhYycdl”), Eq(“B234”));

it WILL break at the end of 2.11 on page 38. I believe you handle the problem with keeping a consonant when there are vowels inbetween later on.

2013-05-06Do you mean change it to something like "AAaEeIiOoUuHhYycdl", i.e. starting with a vowel? That will indeed break. It didn't break when I replaced the C with a B, however. \n \nIt's giving me a headache to even think about right now. :-) When I get the time, I'm going to re-run through the whole example along with the text, a painful exercise, but for now I'm going to sneakily ignore the issue since it does get resolved later in the book. (So I'm marking this as close, but am taking note of it.)
40ERROR

Method isVowel uses ::tolower, should use lower-method instead and read
return std::string(“aeiouy”).find(lower(letter)) != std::string::npos;

2013-05-06
44SUGGEST

Remove #include . Not used anywhere in the code.

2013-05-06
65SUGGEST

std::string createCommand(const std::string name) const
should take a const reference as argument, not copy by value.

2013-05-06
75SUGGEST

Consider always nulling pointers you delete. It’ll easier pick any wrong doings in the test code.
void TearDown() {
delete tweet; tweet = nullptr;
}

2013-05-06
176SUGGEST

RAII is not defined — it would probably be helpful for less-experienced C users or users coming from other languages like Java or C# to define what RAII is, how it works with scope and the stack, and what its advantages are.

2013-05-06
85TYPO

Missing a space after the period, and “Unintentially” should be “Unintentionally”:

“correct order.Unintentially”

2013-05-06
13ERROR

(Error in Extract “Introduction”)
Page 13: Link to agileinaflash.com is not valid.

2013-05-06
80TYPO

Trailing in line
./test —gtest_filter=Retweet.:ATweet.:-ATweet*.Construct

2013-05-06
205SUGGEST

Boost is a heavy dependency to download and install for the wave reader project. Also, I wasn’t able to get rlog to build on OS X Mountain Lion. It would be nice to be able to follow this project without having these extra dependencies.

2013-05-06Agreed, it's a heavy dependency since filesystem is not a header-only library. Fortunately it builds fairly easily. I did get it going on OS X, and have updated the setup chapter to contain pertinent instructions. Unfortunately it'll be unlikely at this point that I get rid of it. Still, the filesystem stuff isn't that large; it is possible I could code it myself (or, hint, someone perhaps contribute the appropriate code).
205ERROR

If the format specifiers for rlog are following printf, then they should be adjusted:

“riff header size = %lu”
“subchunk header size = %lu”
“data length = %u”

Based on compiler warnings from llvm.

2013-05-06
207ERROR

After adding WavReader::dataLength, the code does not compile because the book does not mention that a declaration will also need to be added to the header file.

2013-05-06Hi Kevin-- \n \nCan you point out which source example this is (with the full directory name)? e.g. "wav/13/WavReader.cpp" \n \nPlease update this if you get a chance (or add a new one if the errata system doesn't let you update it). I may have to mark it fixed for the time being. \n \nThanks, \nJeff
200SUGGEST

Should explain what a “slicing” problem is — this isn’t something encountered in other languages like Java, where everything is a reference.

2013-05-06
9viiSUGGEST

First paragraph… In the e-book, I suggest making the phrase “Tiobe index of programming language popularity” a link so readers can see the current standing.

2013-05-06
23TYPO

“Unfortunately, JsonCpp requirea Scons”
should be “Unfortunately, JsonCpp requires Scons”

2013-05-06
192TYPO

“It also does not support all platforms due to little/big endian differences.”

Will this be addressed?

2013-05-06Probably not. Are you unable to run the application on a certain platform? It runs under Ubuntu and MacOS; haven't tested it on Windows.
112TYPO

NickMock mentioned twice. NiceMock is intended.

2013-05-06
67SUGGEST

Not sure if this is a typo, or if I’m just not understanding something:

In section 3.7 Mechanics for Success

test name MustConstructWithTableMetadata
implementation return member variable from accessor

2013-06-02
74SUGGEST

The following reference to “test file” confused me, and I don’t think the “Setup and Teardown” section even mentions more than one test file per class:

“Good reasons exist to have more than one test file per class—don’t ever feel
constrained to only one. Read Setup and Teardown,on page 75 to understand
when you might want more than one test file per class.”

I assume you are saying that (assuming gtest) it wouldn’t be unusual to have multiple classes that derive from testing::test — each declared and implemented in a separate file — and all such classes testing the same SUT.

2013-06-02
79SUGGEST

Maybe this is nit-picking. You write:

“Given—When—Then: Given a context, when the test invokes some behavior, then some result is verified.”

I think you should say something along the lines of, “When the test invokes some SUT API (s), then some behavior is verified.”

2013-06-02
80SUGGEST

Re: 51681.

In fact you do expressly indicate that the test verifies behavior in the very next sentence and paragraph:

"… an understanding of
the behavior your test verifies.) … your focus when doing TDD is on verifying behavior, not executing tests.

2013-06-02
80TYPO

“You’ll learn how to begin breaking those dependencies on slow collaborators
in Test Doubles on mocks.”

2013-06-02
99TYPO

“You’ll learn about different ways of setting up your code so
that it can use test doubles (also know as injection techniques.”

know -> known
. -> ).

2013-06-02
119SUGGEST

You write,
“In some circumstances, you might find it more appropriate to pass the test double using a setter member function. Injecting a test double in this manner is known as (what else?) constructor injection or setter injection.”

Suggest the last sentence be re-written something like, “These alternative ways to inject a test double are known as . . .”

2013-06-02
123SUGGEST

I’d bet that the virtual destructor was cut-and-paste from before the class was made into a template and that you didn’t really mean it:

virtual ~PlaceDescriptionServiceTemplate() {}

2013-06-02
129SUGGEST

You sum up 4 paragraphs of bad outcomes with the following:

“The lesson I learned: Bad dependencies in tests can create significant problems, just as can bad
dependencies in production code. But in hindsight, the inadequate system design was a far
larger problem than the excessive mocking.”

Your conclusion seems (to me) to be impossible to reach given the information provided in the preceding 4 paragraphs. Maybe you should add some more context or explanation.

2013-06-02
129TYPO

The
highly-regarded book, Growing Object-Oriented Software, Guided by Tests
[FP09] by Freeman and Nat Pryce, focuses on using TDD to grown out a system
in this manner.

grown out -> grow out? (flesh out, incrementally grow, build?)

2013-06-02
136SUGGEST

Let’s work through developing a small subsystem
and see how Beck’s notion of simple design plays out.
You write,

"Story: Portfolio Manager
Investors want to track stock purchases and sales, to provide the basis for financial analysis.

We’ll take a look momentarily at a starter set of code for this story, right after
you’re clear on why eliminating duplication is so important."

To say we’re going to work through developing and to provide the Story — then to switch gears and bring in a new document section — was kind of jarring and didn’t make sense to me.

2013-06-02
168TYPO

TDD supports incremental and iterative developmenet through its core cycle
of specify, build, refactor, repeat.

developmenet -> development

2013-06-02
181TYPO

Some elements don’t belong in tests at are.

are -> all

2013-06-02
194TYPO

Our customer has asked us to resolve of
these limitations (leaving the rest to you for future incorporation).

resolve of -> resolve all of

2013-06-02
194TYPO

It seemed quicker at first, but the lack of tests
quickly burned past any time saved as I fell into a couple defect weed patches.)

couple defect -> couple of defect

2013-06-02
208TYPO

TEST_GROUP(WavReader) {
};

Shouldn’t this be TEST_GROUP(WaveReader_WriteSamples){…}?

2013-06-02
211SUGGEST

I got really lost with what you mean here (among other things, the name ‘execute’ does nothing for me):

“The size() function defined on FileUtil would create an ifstream, then pass it to the StreamUtil size(). You might consider this function to be so small as to not break, and consider not writing a unit test for it. Better: Create a single FileUtil function execute() that passes the ifstream to a function object. Client code would pass an appropriate function; for example: …”

2013-06-02
221TYPO

You can read extensively about the technique in .

2013-06-02
234TYPO

The Mikado Method book ()
will supply you with everything you’ll want to know.

2013-06-02
248TYPO

The second test for the Work class, CanExecuteOnDataCapturedWithFunction,
merely shows how lambdas work and is technically not necessary.

second -> last

Also, is the next to last test also not technically necessary?

2013-06-02Thanks for all the great feedback Steve! \n \nThe second to last test verifies that the Work object delegates to the callback.
252TYPO

The challenge with an asynchronous call is that may complete long before
the work gets executed.

that may -> that it may

2013-06-02
257TYPO

unsigned int NumberOfWorkItems{10};
unsigned int NumberOfThreads{10};
for (unsigned int i{0}; i < NumberOfWorkItems; i)
threads.push_back(
make_shared([&] {
for (unsigned int j{0}; j < NumberOfWorkItems; j)
pool.add(work);
}));

NumberOfWorkItems -> NumberOfThreads in the outer loop

2013-06-02
258TYPO

To find
the remaining problems, one analysis tactic is to think about any “gaps” we
have—where we make an assumption about a fact that might no longer be
true, due to the actions of other obstreperous threads.

Last comma is extraneous (sorry to be pedantic, but I had to say it after reading about ‘obstreperous’ threads).

2013-06-02
259TYPO

Unfortunately, this test has the potential to fail, on the rare occasion that
one of the threads processes all of the work items.

See? Once you let one extraneous comma in, they start showing up everywhere. Last comma is unwelcome.

2013-06-02
268TYPO

Following the TPP
allows you to grow your system using the smallest possibly increments.

possibly -> possible

2013-06-02
270SUGGEST

Introducing that code would represent the transform (unconditional→if), which is just a bit further down in priority than (constant→scalar):

Suggest you conclude this sentence with:

, so we choose the higher priority constant->scalar transform:

2013-06-02
271ERROR

This is probably a topic for some discussion forum, but I add it here as a reminder:

std::string encode(const std::string& word) const {
➤ std::string code(“”);
➤ code += word[0];
➤ if (word[1])
➤ code += “100”;
➤ else
➤ code += “000”;
➤ return code;
}

The above code and that in the next few iterations seem to assume the a std::string is like a null-terminated c-string. But std::string is not by default null-terminated. E.g., std::string s(“abc”); has no ‘\\0’ character.

1 - don’t know how your early tests worked

2 - the later refactoring’s removed the null-termination assumptions, so I guess all’s well that ends well. But you might consider devoting some commentary to this in the book text.

2013-06-30Hi Steve, \n \nThe tests do all run. :-) \n \nIt's late in the game and I'm mind-numb from finishing the draft of the book (plus I'm not all that bright at times). Can you supply a bit more specifics about this? (Maybe write a test that demonstrates the potential problem.) \n \nThanks, \nJeff
274TYPO

In later versions of the TPL, you’ll find slight variations on the ordered.

ordered -> order??

That
transformation to a recursive solution is of slightly higher priority than
transforming to a while loop has been a topic of debate.

That -> The fact that??

2013-06-02
288TYPO

First, a fabricated conversation will prepare you for typical questions,
by providing some brief but strong elevator-pitch answers.

Extraneous trailing comma.

2013-06-02
289TYPO

In a code base growing to a large size over time, things that
might have take a couple hours to accomplish can bloat to taking several days.

take -> taken

2013-06-02
293TYPO

Hopefully, you’ve learned in this book that TDD requires you to constrain the scope of each test, so that it tests a small piece of isolated logic.

Extraneous trailing comma.

You and your team must actively seek to squash poor design, in both the tests and the code.

Either extraneous trailing comma, or you really wanted:

You and your team must actively seek to squash
poor design — in both the tests and the code.

2013-06-02
304TYPO

You might even
find

2013-06-02can't find this text in the book any more, I think it's fixed...
313TYPO

Extracting a common function would work to eliminate the duplication,
but seems less than stellar since two separate elements are changing
(the Arabic total and the Roman string).

Either extraneous trailing comma or —

2013-06-02
34TYPO

“less wasted for developers” => “less wasted TIME for developers”

2013-06-28
89TYPO

“a single-line declarative assert that ensure an exception is thrown” => “… ensures …”

2013-06-28
98TYPO

“you’re read to tackle” => “you’re ready to tackle”

2013-06-28
4SUGGEST

Aloha. First of all, AWESOME BOOK. I have been dying for this exact book for years. Thank you! I love that the information is distilled and there is almost no filler. That being said, I’m an experienced programmer but have never used Google’s Test or Mock before, nor have I used testing libraries that cannot be installed system-wide, i.e. with `make install`. For that matter I haven’t previously done testing with frameworks, hence my insta-purchase of this book. Anyways, Google Test/Google Mock doesn’t behave this way and it took some Googling and reading (and thinking) on my part to understand this. The pages and tutorials on Google Code do not explicitly mention this. While another page of installation instructions would be burdensome, I think it would be very helpful to inexperienced readers if you include a small paragraph in the GoogleMock/Test setup section explicitly mentioning that the libraries cannot be precompiled for system-wide access, that the framework must be specified as compiler/linker flags/options during the same compilation as those of the tests we are writing. Something like that would have saved a good eight hours of evening/weekend time. That sounds ridiculous, I know, but like I said this is my first time testing in C and with a framework that can’t be installed system-wide. Aloha and thanks again for the incredible book! I can’t wait to get the printed edition into my hands!

2013-06-28Thanks Curtis! Sorry for your wasted time. \n \nI'm trying to tweak the setup instructions a bit to make things more clear with respect to building and Google Mock.
7ERROR

The text at the end of section 1.8 refers to the libjson shared library (.so), but the instructions describe linking to the archive file.

2013-06-30
57SUGGEST

Use unsigned numeric constants when assigning or comparing with unsigned values in the code. Replace all code example 0:os with 0u. (or 0U). Five places. First one also causes a compiler warning. ASSERT_THAT(collection.size(), Eq(0u));

2013-08-30
58SUGGEST

Use unsigned numeric constants when assigning or comparing with unsigned values in the code. Replace all code example 1:s with 1u. (or 1U). Two places. Last one also causes a compiler warning. ASSERT_THAT(collection.size(), Eq(1u));

2013-08-30
59SUGGEST

For consistency with page 57 and 58
“return 0;” to “return 0u;”
and
“return isEmpty() ? 0 : 1;” to “return isEmpty() ? 0u : 1u;”

2013-08-30Thanks Bo. I got rid of the warnings, I'm going to leave it at that in order to close things out.
46TYPO

… now encodes the entier word…

2013-08-29
6TYPO

Top of page reads “…for some proposed C++14 features
proposed.” Drop last `proposed’.

2013-08-30
122ERROR

I couldn’t find OutParameterTest.cpp in the repo, but the sample in the book appears to be incorrect. Here is an updated version:

DifficultCollaboratorMock difficult;
EXPECT_CALL(difficult, calculate(_))
.WillOnce(DoAll(
SetArgPointee<0>(3),
Return(true)));
int target;

auto result = difficult.calculate(&target); // ignore return value in this test?

ASSERT_THAT(target, Eq(3));

2013-08-30Thanks Bradford, \n \nThat actually reverses the dependency. Here's the entire source file: \n \n#include "gmock/gmock.h" \n \nusing namespace ::testing; \n \nclass DifficultCollaborator { \npublic: \n virtual bool calculate(int* result) \n { \n throw 1; \n } \n}; \n \nclass Target { \npublic: \n int execute(DifficultCollaborator* calculator) { \n int i; \n if (!calculator->calculate(&i)) \n return 0; \n return i; \n } \n}; \n \nclass DifficultCollaboratorMock: public DifficultCollaborator { \npublic: \n MOCK_METHOD1(calculate, bool(int*)); \n}; \n \nTEST(ATarget, ReturnsAnAmountWhenCalculatePasses) { \n DifficultCollaboratorMock difficult; \n Target calc; \n EXPECT_CALL(difficult, calculate(_)) \n .WillOnce(DoAll( \n SetArgPointee<0>(3), \n Return(true))); \n \n auto result = calc.execute(&difficult); \n \n ASSERT_THAT(result, Eq(3)); \n} \n \nIt does work, though I admit it's a bit confusing. \n \nRegards, \nJeff
171TYPO

“You must take advantage of the opportunity that each a passing test provides you”

2013-08-29
192TYPO

“Immediate understanding disappers…”

2013-08-29
193TYPO

“softare design.”

2013-08-29
196TYPO

“which would involved changing existing”

2013-08-29
9ERROR

To install CppUTest, ‘./configure’ need before ‘make’. and ‘make’ also builds CppUTestExt. ‘make install’ copies the library to common path ‘/usr/local/lib’

—- before —-
cd $CPPUTEST_HOME
make
make -f Makefile_CppUTestExt

—- suggestion —-
cd $CPPUTEST_HOME
./configure
make
make install

2013-08-30Thanks for the info. I added the ./configure. The other change applies only to v3.4 of CppUTest, which came out too late for me to accommodate it into the book.
10ERROR

scons script has permission to excute. I tested Mac and Linux platform, Just ‘scons platform=linux-gcc’ makes success. - But ‘python scons platform=linux-gcc’ doesn’t work.

—- before —-
python scons platform=linux-gcc

—- suggestion —-
scons platform=linux-gcc

2013-08-30
255TYPO

In ThreadPoolTest one lock call uses std:: and one does not

2013-08-29
293TYPO

“so none of its lines is highlighted”

2013-08-30it's possible to use both "none are" and "none is" depending on context. I'm checking with my editor. ... Editor says it's ok.
86TYPO

On page, 86 of Beta version 5, there is the following sentence : “The concept of AAA won’t shatter any earths, …”. However, I believe the author is trying to use the English phrase, “The concept of AAA isn’t earth shattering, …”

2013-08-29thanks Scott, it's a deliberate twisting of the phrase, to be different. I'll ask the editor if they think it's inappropriate. ... Editor did say it was ok.
35ERROR

RLog installation for OSX are not working.

- the diff file does not exist in the source code specified folder (I manually diffed though)
- atutoreconf command is not working

any suggestions?

Thank you
Sherief

2013-08-30Greetings Sherief, \n \nMy apologies for your problems with this library. My recommendation would be to skip ahead to the part where you create a link stub--you really don't need a working rlog. \n \nSomehow I did manage to do all that stuff with the patch to get it to work, unfortunately it'll probably be a few weeks before I can get back to looking at building on a mac.
6.1SUGGEST

Pet peeve of mind…

Prefer forward declarations to including header files. In section 6.1 in Portfolio.h just forward declare std::string and include in Portfolio.cpp.

From “C Programming Standards: 101 Rules, Guidelines, and Best Practices” rule 22.

P.S. Reading this on my Kindle (no page numbers in Kindle, just 4782 of 11562 (41% of the way through the book).

2013-08-30Thanks Michael, \n \nI probably missed a few opportunities to do forward declare. I'm all for it wherever possible. \n \nCan you forward declare std::string? \n \nFor now I'll have to leave things where they are.
134TYPO

work “flesh” is used in few places, I think you mean “flush” there

2013-08-29Thanks for the feedback. See http://www.merriam-webster.com/top-ten-lists/top-10-commonly-confused-words-vol-2/flush-out-flesh-out.html. \n \nI appreciate your pointing this out, because it is certainly a phrase I use too often--a grep shows that I use it 12 times in the book. I cut it down to 3 uses in the entire book.
288TYPO

In my comment “#52372: work” I mean “word” , sorry for my typo.

I have completed upto 5 chapters now and I wanted to point out that you are using web related examples, I was expecting some other examples as C programmers work more towards system side and Java programmers can deal with web related stuff.

2013-08-29Thanks for the feedback. I do apologize for the emphasis on application examples. None of them are technically "web," though of course they could be. Soundex focuses on algorithmic development, tweets, portfolio, & library are of course application development, geoserver and place description services are server side of application development, and wav is utility development. So, nothing on the side of system development. It's of course too late to change the examples. I realize it's easier to relate to examples in your sphere of experience, but unfortunately it's too late to make any such changes to the examples used. I also chose examples that would make it easy for readers to follow; I've been far more disappointed by books that use examples which are difficult to follow because of the esoterica of the domain.
144SUGGEST

Can you please give a better name to shares_
It does not describe what it is?
It could be numOfShares…

2013-08-29
1SUGGEST

Please remove trailing spaces from source code files.

2013-08-30Thanks for the suggestion. I removed it from some of the source files, but at this point it's a very time consuming effort to ensure all trailing spaces are removed from all files in all branches. Sorry about that.
144SUGGEST

Shares() is the function name.
The meaning is not clear from its name.
It should be getNumOfShares() atleast to be clear.

2013-08-29
148SUGGEST

Can you please change names in below function
Sell(const std::string& symbol, unsigned int shares)

symbol ———-> symbolOfShare
shares ———-> numOfSharesToSell or numOfShare

This is just a suggestion.

2013-08-29
252TYPO

This is not how to use allay.

“The test serves to allay our still-growing knowledge of how to use lambdas” -> “allay uncertainty about”

2013-08-29
64ERROR

“changebar” triangle missing left of return statement for

unsigned int size() const {
return size_;
}

2013-08-30
65SUGGEST

ASSERT_THAT(collection.size(), Eq(1)); should use unsigned 1 to avoid compiler warning with gcc.

ASSERT_THAT(collection.size(), Eq(1u));

2013-08-30
66SUGGEST

Second last line should read
ASSERT_THAT(collection.size(), Eq(0u));
to avoid compiler warning.

2013-08-30
67SUGGEST

Change ASSERT_THAT(collection.size(), Eq(0));
to ASSERT_THAT(collection.size(), Eq(0u));
to avoid compiler warning.

2013-08-30
67SUGGEST

Change ASSERT_THAT(collection, HasSize(0));
to ASSERT_THAT(collection, HasSize(0u)); avoids compiler warning.

2013-08-30
67ERROR

“The MATCHER_P macro in Google Test defines…”
should read “The MATCHER_P macro in Google Mock defines…”.

2013-08-29
68SUGGEST

Both Eq(0) and Gt(0) should read Eq(0u) and Gt(0u) to avoid compiler warning.

2013-08-30
71SUGGEST

Change ASSERT_THAT(collection.size(), Eq(1)); to ASSERT_THAT(collection.size(), Eq(1u)); to avoid compiler warning.

2013-08-30
79SUGGEST

Bottom of page: “Decide on a naming scheme, such as BehaviorDescriptionTest or TestBehaviorDescription or BehaviorDescriptionTests.cpp.” Sentence is a bit confusing reading it quickly.

Suggest adding .cpp on all schemes or leaving it out on all.
Move the first and third scheme closer to easier see you playing with ‘…Test’ and ‘…Tests’.

2013-08-29
80ERROR

“Google Mock” mentioned twice on page, but should read “Google Test” since fixtures are part of Google Test and not Google Mock.

2013-08-29thanks Bo. I put a disclaimer up front about this--I decided to simplify and use the term Google Mock most of the time, regardless of where the feature is implemented.
81ERROR

“Google Mock” (mentioned three times) to be replace with “Google Test” since fixtures are part of the Google Test framework and not Google Mock.

2013-08-29
82SUGGEST

ASSERT_THAT(collection.size(), Eq(1)); (used twice) should be ASSERT_THAT(collection.size(), Eq(1u)); to avoid compiler warning.

2013-08-30
82ERROR

Last paragraph on page “(Google Mock… ” should read (Google Test… " since this is part for the basic Google Test functionality.

2013-08-29
83SUGGEST

Top of page, replacing “ASSERT_THAT(collection.size(), Eq(1));” with “ASSERT_THAT(collection.size(), Eq(1u));” takes care of compiler warning.

2013-08-30
84SUGGEST

Using ASSERT_THAT(collection.size(), Eq(1u)); instead of ASSERT_THAT(collection.size(), Eq(1)); avoids compiler warning.

2013-08-30
87ERROR

Replace “Goole Mock” with “Google Test”. gtest handles the filtering.

2013-08-29
88ERROR

Four times “Google Mock” to be replaced by “Google Test”. This is gtest functionality.

2013-08-29
88ERROR

Google Mock to be replaced by Google Test.

2013-08-29
89ERROR

Google Mock to be replaced by Google Test. (Last comment just refered to wrong page. Sorry for the spam.)

2013-08-29
93TYPO

“ASSERT_EQUALS()” should be “ASSERT_EQ()” found on last line before heading “Comparing Floats”

2013-08-29good catch
94SUGGEST

Possibly stick to the Hamcrest notation for comparing floats. I.e., show ASSERT_THAT(x - y, FloatEq(9.9)) and ASSERT_THAT(x - y, FloatNear(9.9, 0.05));

Also, if you want to expand you can mention one reason ASSERT_EQ(x-y, 9.9) doesn’t work is 9.9 is double. Had you written 9.9f, which is a float, the strange fail might go away.

2013-08-30thanks for catching this!
44ERROR

On OS X Mavericks DP6 I had to ‘#import ’ at the top of SoundexTest.cpp to make it compile. I’m using macport’s gcc47. Xcode DP6 is installed with command line tools.

Without I got:
/Users/claus/devel/tdd/SoundexTest.cpp:5:2: error: ‘string’ in namespace ‘std’ does not name a type
/Users/claus/devel/tdd/SoundexTest.cpp: In member function ‘virtual void SoundexEncoding_RetainSoeLetterOfOneLetterWord_Test::TestBody()’:
/Users/claus/devel/tdd/SoundexTest.cpp:15:25: error: ‘class Soundex’ has no member named ‘encode’
/Users/claus/devel/tdd/SoundexTest.cpp:15:35: error: unable to deduce ‘auto’ from ‘
/Users/claus/devel/tdd/SoundexTest.cpp:15:7: warning: unused variable ‘encoded’ [-Wunused-variable]

Maby something specific to my setup?

Regards
Claus

2013-08-30Thanks Claus, \n \nI invite you to join the Google Group (https://groups.google.com/forum/#!forum/modern-cpp-with-tdd), and would be thankful if you'd post this and any similar messages about build specifics there. I think it's specific to your configuration. \n \nRegards, \nJeff
11TYPO

patch instructions for the OS X install are missing a “-i” flag, i.e line should read:
patch -p1 -i [path to file]/rlog.diff

I copied the text in the comment to a file and saved it locally. Also I had to install autoreconf using “sudo port install automake autoconf libtool”. Finally had to run “automake —add-missing” prior to running autoreconf

86TYPO

“hapharzardly” -> should be “haphazardly”

107ERROR

The code examples at pragprog.com/titles/lotdd/source_code for chapter 5 no longer work with Google Mock 1.7 :-(
You get compiler errors about ambiguous IsEmptyMatcher in c5/1/AddressExtractorTest.cpp.
The root cause is a new matcher in gmock 1.7 with the same name (defined in file gmock-more-matchers.h)! It’s defined in namespace testing but since we open up the testing namespace in the book code the compiler now has two matcher to choose from.
A couple of solutions proposals.
1) Wait with opening the testing namespace until after last use of the IsEmpty-matcher. Thus,
class AnAddressExtractor: public Test {
becomes
class AnAddressExtractor: public testing::Test {
and add using namespace testing; ReturnsAnEmptyAddressWhenNoAddressFound.

2) Add a namespace around at least the definition of the matcher and its use. Anonymous namespace will do.

3) Rename the matcher from IsEmpty to something else not already defined within the namespace testing from Gmock.

160SUGGEST

In the middle of the first paragraph you write:

“… (first inserting an empty vector if needed).”

It’s not needed. The code

auto it = purchaseRecords_.find(symbol);
if (it == purchaseRecords_.end())
purchaseRecords_[symbol] = vector();
purchaseRecords_[symbol].push_back(PurchaseRecord(shareChange, date));

could just has well been written:

purchaseRecords_[symbol].push_back(PurchaseRecord(shareChange, date));

since operator[] adds an empty record if it doesn’t already exist. No need to repeat the implicit search with operator[].

161SUGGEST

c6/17/Portfolio.h
Template interface should either be

T Find(const std::unordered_map<std::string, T>& map, const std::string& key) const

Or, the whole implementation could be
{
return map[key];
}
since the the container is copied with the original interface. operator[] does all the magic for unordered_map but doesn’t work on a consted unordered_map.

166SUGGEST

End of second paragraph read (Look at the
source download to see the final tests.)

Looking at the source code downloaded from the book site there is a empty directory c6/20. Is that where the reference goes? In that case the code is missing :-)

204ERROR

In “4. We copy the for loop …” the code shows

rLog(channel, “writing %i samples”, samplesToWrite);

but should be

rLog(channel, “writing %u samples”, samplesToWrite);

as the code read in version 3. And it’s pretty obvious now since the declaration of samplesToWrite is just two lines above, uint32_t.

211SUGGEST

Consider using nullptr instead of 0 as the return value for
RLogChannel *getComponent(RLogChannel *componentParent,
const char *component){ return 0; }
}

It’s more modern C :-)

20TYPO

On Ubuntu 13.10 I had the following linking errors regarding pthread in the chapter 2 exercises:

undefined reference to `pthread_getspecific’

In order to fix this, I had to change the order of the CMakeLists.txt file from:

target_link_libraries(test pthread)
target_link_libraries(test gmock)
target_link_libraries(test gtest)

to:

target_link_libraries(test gmock)
target_link_libraries(test gtest)
target_link_libraries(test pthread)

192TYPO

The bad example code and the improved" version at the bottom of the page are exactly the same.

192TYPO

1st paragraph, last sentence:
but others wom’t -> but others won’t

192TYPO

Except for the increased indentation is HoldingServiceTest.cpp identical in Branches 18 and 19.

The execution statement is isolated in Branch 20.

7ERROR

Maverick (OS X 10.9) changed the default stdlib library.
To get Ch.2 examples working, I had to force gmock to build with libc.
Use:
./configure CXX=“clang -std=c+11 -stdlib=libc+” && make

I also needed to add a couple of symbolic links:
cd $GMOCK_HOME
ln –s lib/.libs mybuild
cd gtest
ln –s lib/.libs mybuild

and add this env variable to ~/.bash_profile:
export DYLD_FALLBACK_LIBRARY_PATH=$GMOCK_HOME/lib/.libs:$GMOCK_HOME/gtest/lib/.libs:$DYLD_FALLBACK_LIBRARY_PATH

For jsoncpp in Ch.5, I had to edit the SConstruct file:
elif platform.startswith(‘linux-gcc’):
env.Tool( ‘default’ )
env[‘CXX’] = ‘clang -stdlib=libc’ #scons does not pick-up the correct one !

and add a symbolic link:
$ cd $JSONCPP_HOME/libs
$ ln -s linux-gcc-4.2.1/libjson_linux-gcc-4.2.1_libmt.a libjson_linux-gcc.a

9TYPO

Download the appropriate file and unpack, perhaps into a new directory named pputest within your home directory.
pputest should be cpputest.

125TYPO

If I understand the example correctly httpServer() should be replaced with httpService() in the following section:
“With respect to our example, the difference is that the httpServer() function is a simple getter that returns a member variable referencing an existing instance, whereas in Override Factory, httpServer() is responsible for constructing the instance.”

20SUGGEST

You wrote:

“To compile, we added an empty declaration for the Soundex class.”

It should be:
“To compile, we added an empty definition for the Soundex class”

51SUGGEST

1. The Soundex class / algorithm mentions the case of unrecognised characters, and tests for them with the IgnoresNonAlphabetics test. However, it does not mention or demonstrate whether we should treat encodings on either side as separate (i.e. the same as separated by a vowel) or not. Another test DoesNotCombineEncodingsSeparatedByUnrecognisedCharacters or DoesCombineEncodingsSeparatedByUnrecognisedCharacters would be a good idea.

2. The Soundex encodings map should probably contain characters instead of std::strings. Doing this from the start makes it more interesting from the point of view of handling invalid characters, as well as indicating another reason for the NotADigit constant (i.e. std::optional doesn’t exist yet), vs using an empty string as NotADigit.

85ERROR

There is no difference between the code samples trying to show the Arrange, Act, Assert, and the code that makes it obvious about the different sections. Did the white space get removed in Kindle sample?

In the Kindle version of the book on page 85/334. I don’t think it’s correct, but I’m not sure what I should be seeing as described in the text between the code blocks

The mnemonic Arrange, Act, Assert (AAA, usually spoken as triple-A), devised by Bill Wake,[ 10] reminds you to visually organize your tests for rapid recognition. Looking at this next test, can you quickly discern which lines of the test relate to setting up a context, which line represents execution of the behavior we want to verify, and which lines relate to the actual assertion?

c3/ 14/ RetweetCollectionTest.cpp TEST_F( ARetweetCollection, IgnoresDuplicateTweetAdded) {     Tweet tweet(" msg“, ”@ user");     Tweet duplicate( tweet);     collection.add( tweet);     collection.add( duplicate);     ASSERT_THAT( collection.size(), Eq( 1u)); }                       
With the lines clumped together, it takes a few extra moments to see exactly what’s being tested. Contrast that version of the test with code that makes the Arrange, Act, and Assert portions of the test obvious.

c3/ 13/ RetweetCollectionTest.cpp TEST_F( ARetweetCollection, IgnoresDuplicateTweetAdded) {     Tweet tweet(" msg“, ”@ user");     Tweet duplicate( tweet);     collection.add( tweet);     collection.add( duplicate);     ASSERT_THAT( collection.size(), Eq( 1u)); } 

Langr, Jeff (2013-10-10). Modern C Programming with Test-Driven Development: Code Better, Sleep Better (p. 85). Pragmatic Bookshelf. Kindle Edition.

109ERROR

Minor issue if you follow along from the first c5/1 code as a starting point. The test will pass verify on page 109 kindle.

c5/1 code does not fail the verify() assertion for PlaceDescriptionTest(), since it already implements the logic for creating a URL that ends with the lat/lon.

c5/2 and c5/3 do fail summaryDescription, since they both pass in “” URLs

192ERROR

Page 192/334 links to the wrong code sample.

1. There is no change in the whitespace for the “Misleading Organization” unit test X.
2. It should link to c7/20/libraryTest/HoldingServiceTest.cpp, not c7/19/libraryTest/HoldingServiceTest.cpp
3. The text should clarify that this is a white space change, which groups the test code into 3 sections (AAA).

Last function in link:
media.pragprog.com/titles/lotdd/code/c7/18/libraryTest/HoldingServiceTest.cpp

TEST_F(HoldingServiceTest, X)
{
HoldingBarcode barcode(THE_TRIAL_CLASSIFICATION, 1);
string patronCardNumber(“p5”);
CheckOut(barcode, branch1, patronCardNumber);
date_duration oneDayLate(Book::BOOK_CHECKOUT_PERIOD + 1);
holdingService.CheckIn(barcode.AsString(),
*arbitraryDate + oneDayLate, branch2->Id());
ASSERT_THAT(FindPatronWithId(patronCardNumber).FineBalance(),
Eq(Book::BOOK_DAILY_FINE));
}

media.pragprog.com/titles/lotdd/code/c7/20/libraryTest/HoldingServiceTest.cpp

TEST_F(HoldingServiceTest, X)
{
HoldingBarcode barcode(THE_TRIAL_CLASSIFICATION, 1);
string patronCardNumber(“p5”);
CheckOut(barcode, branch1, patronCardNumber);
date_duration oneDayLate(Book::BOOK_CHECKOUT_PERIOD + 1);
// Add newline

holdingService.CheckIn(barcode.AsString(),
*arbitraryDate + oneDayLate, branch2->Id());
// Add newline

ASSERT_THAT(FindPatronWithId(patronCardNumber).FineBalance(),
Eq(Book::BOOK_DAILY_FINE));
}

By adding spaces between the setup, method in test, and assertion allows someone to quickly scan for the relevant information.

22TYPO

“On failure, the lines between [RUN] and [OK] might help us understand our failure.”
-> “the lines between [RUN] and [FAILED]”

22TYPO

“On failure, the lines
between [ RUN ] and [ OK ] might help us understand our failure. ”

[ OK ] should be replaced with [FAILED]

28TYPO

The last line of page 28 “If we forget to use TEST_F, any test code attempting to use fixture member errors will fail compilation.” has typo.

100ERROR

Code for chapter 8 and 9 does not compile under Ubuntu 19.04.

:true_type)’:
/usr/include/c/8/bits/std_function.h:164:11: error: ‘__dest’ does not name a type
::new (__dest._M_access()) Functor(_source._M_access<_Functor>());

9TYPO

At the end of the 2nd paragraph: … new directory named pputest within your home directory.

‚pputest‘ should be ‚cpputest‘.

185SUGGEST

In the helper method ASSERT_EQUAL_WITH_LENGTH the paramter ‚length‘ is checked against strlen(actual) which comes from ‚len‘. Checking length against strlen(expected) would fail if the function GetNextLine returns an unexpected value for len.

Categories: