2.1 to 2.3 Three tests of counting
Build it yourself. Read the tutorial is the other way to read this part.
If you start at this part, make your clone as Get the project says, and then run this command. It puts in your clone the files that this part starts from. A file that the project deleted before this part stays, so delete it if git check lists it:
git rm -rq --cached --ignore-unmatch -- :/ && git restore --source eb951f747563 --staged --worktree -- :/just setuptally counts words already. The function count and the command are there, and this walk begins with them.
Nothing checks yet that they count right.
The code before this part. The code after it.
2.1 A test of counting
Nothing checks yet that count gives the right counts. A test of unittest, the test library of Python, calls
count on a short text and compares the result with the dictionary that it expects. The tests go in a new folder,
tests.
Make the folder, and run the tests in it. The folder has no tests yet, so unittest prints NO TESTS RAN.
mkdir -p tests
uv run python -m unittest discover -s tests -qThe first file of tests, tests/test_count.py, has two tests. test_words counts a b a. test_case counts
A a, and expects the one word a, twice. The code cannot do this yet.
Apply the patch to tests/test_count.py, from the top of the project:
curl -fsSL https://github.com/rahuldave/tally/commit/6a4b1a0e50035c4060f84b50770e234b2156be10.diff | git apply --include=tests/test_count.pyThe patch makes the file tests/test_count.py, with the class Count and its two tests.
uv run python -m unittest discover -s tests -qOne test fails. test_case expects {'a': 2}, and gets {'A': 1, 'a': 1}. The failure is a question that the
code has not answered yet.
The first two tests are the pattern for the third. A test gives count a text, and compares what count gives back
with the counts that it must give.
Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:
git check 6a4b1a0e5003If you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:
git restore --source eb951f747563 --staged -- :/ && git restore --source 6a4b1a0e5003 --staged --worktree -- :/What changed
tests/test_count.py: two tests. The second asks for something the code cannot do yet. New, 11 lines. The file.- look at
self.assertEqual(count("A a"), {"a": 2})
- look at
The patch to tests/test_count.py
@@ -0,0 +1,11 @@
+import unittest
+
+from tally import count
+
+
+class Count(unittest.TestCase):
+ def test_words(self):
+ self.assertEqual(count("a b a"), {"a": 2, "b": 1})
+
+ def test_case(self):
+ self.assertEqual(count("A a"), {"a": 2})2.2 A test of an empty text
An empty file is a text with no words. count must give an empty dictionary for it, and not fail. A test in a
file of its own, tests/test_empty.py, says so, and keeps it true after later changes.
Apply the patch to tests/test_empty.py, from the top of the project:
curl -fsSL https://github.com/rahuldave/tally/commit/4f9bfa3d9c08307287e81a631039894490a3e590.diff | git apply --include=tests/test_empty.pyThe patch makes the file tests/test_empty.py, with the class Empty and its test.
uv run python -m unittest discover -s tests -qThe new test passes at once, because split() finds no words in an empty text. test_case still fails.
Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:
git check 4f9bfa3d9c08If you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:
git restore --source 6a4b1a0e5003 --staged -- :/ && git restore --source 4f9bfa3d9c08 --staged --worktree -- :/What changed
tests/test_empty.py: an empty text counts nothing. New, 8 lines. The file.- look at
self.assertEqual(count(""), {})
- look at
The patch to tests/test_empty.py
@@ -0,0 +1,8 @@
+import unittest
+
+from tally import count
+
+
+class Empty(unittest.TestCase):
+ def test_empty(self):
+ self.assertEqual(count(""), {})2.3 Case does not matter
test_case fails, because count counts A and a as two words. When count puts the text in lower case before
it splits it, every word is counted in lower case. One word in the loop of count, lower(), does it.
Apply the patch to src/tally/__init__.py, from the top of the project:
curl -fsSL https://github.com/rahuldave/tally/commit/bfcbe07463b5c6f3c0764e4ac19a054cb0acee20.diff | git apply --include=src/tally/__init__.pyIn count, the patch puts text.lower().split() in place of text.split().
uv run python -m unittest discover -s tests -q
echo "The the" | uv run tallyAll three tests pass, and the command prints 2 the for "The the".
Three tests now say what count does. It counts words, it gives nothing for an empty text, and it ignores case.
Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:
git check bfcbe07463b5If you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:
git restore --source 4f9bfa3d9c08 --staged -- :/ && git restore --source bfcbe07463b5 --staged --worktree -- :/What changed
src/tally/__init__.py: one word,lower(), answers the failing test. 1 line added, 1 removed. The file.- look at
for word in text.lower().split():
- look at
The patch to src/tally/__init__.py
@@ -5,7 +5,7 @@ import sys
def count(text):
counts = {}
- for word in text.split():
+ for word in text.lower().split():
counts[word] = counts.get(word, 0) + 1
return counts