Appendix A on p46 of NIST SP 800-63 talks about the work of Claude Shannon, who estimates password entropy using a number of bits. Indeed, this is the document that the XKCD cartoon uses to calculate the entropy bits. Specifically:
- the entropy of the first character is taken to be 4 bits;
- the entropy of the next 7 characters are 2 bits per character; this is roughly consistent with Shannon’s estimate that “when statistical
effects extending over not more than 8 letters are considered the
entropy is roughly 2.3 bits per character;”
- for the 9th through the 20th character the entropy is taken to be 1.5 bits per character;
- for characters 21 and above the entropy is taken to be 1 bit per character;
- A “bonus” of 6 bits of entropy is assigned for a composition rule that requires both
upper case and non-alphabetic characters. This
forces the use of these characters, but in many cases thee characters
will occur only at the beginning or the end of the password, and it
reduces the total search space somewhat, so the benefit is probably
modest and nearly independent of the length of the password;
- A bonus of up to 6 bits of entropy is added for an extensive dictionary check. If the
attacker knows the dictionary, he can avoid
testing those passwords, and will in any event, be able to guess much
of the dictionary, which will, however, be the most likely selected
passwords in the absence of a dictionary rule. The assumption is that
most of the guessing entropy benefits for a dictionary test accrue to
relatively short passwords, because any long password that can be
remembered must necessarily be a “pass-phrase” composed of dictionary
words, so the bonus declines to zero at 20 characters.
The idea is that an authentication system would pick certain entropy levels as thresholds. For example, 10 bits may be weak, 20 medium and 30 strong (numbers picked arbitrarily as an example, not a recommendation). Unfortunately, the document does not recommend such thresholds, probably because the computational power available to brute force or guess passwords increases over time:
As an alternative to imposing some arbitrary specific set of rules, an
authentication system might grade user passwords, using the rules
stated above, and accept any that meet some minimum entropy standard.
For example, suppose passwords with at least 24-bits of entropy were
required. We can calculate the entropy estimate of
“IamtheCapitanofthePina4” by observing that the string has 23
characters and would satisfy a composition rule requiring upper case
and non-alphabetic characters.
This may or may not be what you are looking for but is not a bad reference point, if nothing else.
[Edit: Added the following.]
The paper Testing Metrics for Password Creation Policies
by Attacking Large Sets of Revealed Passwords (by Matt Weir, Sudhir Aggarwal, Michael Collins and Henry Stern) demonstrated the Shannon model, described above, is not an accurate model of entropy for human generated passwords. I would recommend looking at "Section 5 Generating New Password Creation Policies" for more accurate proposals.
There was no test-driven development process during the development due to very tight deadlines
This statement is very concerning. Not because it means you developed without TDD or because you aren't testing everything. This is concerning, because it shows you think TDD will slow you down and make you miss a deadline.
As long as you see it this way you aren't ready for TDD. TDD isn't something you can gradually ease into. You either know how to do it or you don't. If you try doing it halfway you're going to make it and yourself look bad.
TDD is something you should first practice at home. Learn to do it, because it helps you code now. Not because someone told you to do it. Not because it will help when you make changes later. When it becomes something you do because you're in a hurry then you're ready to do it professionally.
TDD is something you can do in any shop. You don't even have to turn in your test code. You can keep it to yourself if the others disdain tests. When you do it right, the tests speed your development even if no one else runs them.
On the other hand if others love and run your tests you should still keep in mind that even in a TDD shop it's not your job to check in tests. It's to create proven working production code. If it happens to be testable, neat.
If you think management has to believe in TDD or that your fellow coders have to support your tests then you're ignoring the best thing TDD does for you. It quickly shows you the difference between what you think your code does and what it actually does.
If you can't see how that, on its own, can help you meet a deadline faster then you're not ready for TDD at work. You need to practice at home.
That said, it's nice when the team can use your tests to help them read your production code and when management will buy spiffy new TDD tools.
Is it a good idea to write all possible test cases after transforming the team to TDD?
Regardless of what the team is doing it's not always a good idea to write all possible test cases. Write the most useful test cases. 100% code coverage comes at a cost. Don't ignore the law of diminishing returns just because making a judgement call is hard.
Save your testing energy for the interesting business logic. The stuff that makes decisions and enforces policy. Test the heck out of that. Boring obvious easy-to-read structural glue code that just wires stuff together doesn't need testing nearly as badly.
(1) Is it still okay or good idea to stop most of the development and start writing whole possible test cases from the beginning, even though everything is working completely OKAY (yet!)? Or
No. This is "let's do a complete rewrite" thinking. This destroys hard won knowledge. Do not ask management for time to write tests. Just write tests. Once you know what you’re doing, tests won't slow you down.
(2) it's better to wait for something bad happen and then during the fix write new unit tests, or
(3) even forget about previous codes and just write unit tests for the new codes only and postpone everything to the next major refactor.
I'll answer 2 and 3 the same way. When you change the code, for any reason, it's really nice if you can slip in a test. If the code is legacy it doesn't currently welcome a test. Which means it's hard to test it before changing it. Well, since you're changing it anyway you can change it into something testable and test it.
That's the nuclear option. It's risky. You're making changes without tests. There are some creative tricks to put legacy code under test before you change it. You look for what are called seams that allow you change the behavior of your code without changing the code. You change configuration files, build files, whatever it takes.
Michael Feathers gave us a book about this: Working Effectively with Legacy Code. Give it a read, and you'll see that you don't have to burn down everything old to make something new.
Best Answer
Your question implies that TDD has something to do with "writing all test cases first". IMHO that's not "in the spirit of TDD", actually it's against it. Remember that TDD stands for "test driven development", so you need only those test cases which really "drive" your implementation, not more. And as long as your implementation is not designed in a way where the number of code blocks grows exponentially with each new requirement, you won't need an exponential number of test cases either. In your example, the TDD cycle probably will look like this:
Then, start with the 2nd requirement:
Here comes the catch: when you add test cases for requirement/category number "n", you will only have to add tests for making sure that the score of the category "n-1" is higher than the score for category "n". You will not have to add any test cases for every other combination of the categories 1,...,n-1, since the tests you have written before will make sure that the scores of that categories will still be in the correct order.
So this will give you a number of test cases which grows approximately linear with the number of requirements, not exponentially.