Skip to content

Commit e81fa1a

Browse files
jbrukhclaude
andcommitted
Maximize test coverage to 100%
- Add tests for WordsByClass - Add tests for NewClassifierTfIdf edge cases (not unique, too few classes) - Add tests for TF-IDF panics (ProbScores, SafeProbScores, Learn after convert) - Add tests for file operation error paths - Remove unused getWordsProb function (dead code) Coverage improved from 91.9% to 100%. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent f16fb20 commit e81fa1a

File tree

2 files changed

+103
-14
lines changed

2 files changed

+103
-14
lines changed

bayesian.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,6 @@ func (d *classData) getWordProb(word string) float64 {
8080
return float64(value) / float64(d.Total)
8181
}
8282

83-
// getWordsProb returns P(D|C_j) -- the probability of seeing
84-
// this set of words in a document of this class.
85-
//
86-
// Note that words should not be empty, and this method of
87-
// calculation is prone to underflow if there are many words
88-
// and their individual probabilities are small.
89-
func (d *classData) getWordsProb(words []string) (prob float64) {
90-
prob = 1
91-
for _, word := range words {
92-
prob *= d.getWordProb(word)
93-
}
94-
return
95-
}
96-
9783
// NewClassifierTfIdf returns a new classifier. The classes provided
9884
// should be at least 2 in number and unique, or this method will
9985
// panic.

bayesian_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,106 @@ func TestTfIdClassifier_LogScore(t *testing.T) {
392392
fmt.Printf("%#v", score)
393393

394394
}
395+
396+
func TestWordsByClass(t *testing.T) {
397+
c := NewClassifier(Good, Bad)
398+
c.Learn([]string{"tall", "handsome", "rich"}, Good)
399+
c.Learn([]string{"bald", "poor", "ugly"}, Bad)
400+
401+
goodWords := c.WordsByClass(Good)
402+
Assert(t, len(goodWords) == 3, "should have 3 words")
403+
Assert(t, goodWords["tall"] == float64(1)/float64(3), "tall frequency")
404+
Assert(t, goodWords["handsome"] == float64(1)/float64(3), "handsome frequency")
405+
Assert(t, goodWords["rich"] == float64(1)/float64(3), "rich frequency")
406+
407+
badWords := c.WordsByClass(Bad)
408+
Assert(t, len(badWords) == 3, "should have 3 words")
409+
Assert(t, badWords["bald"] == float64(1)/float64(3), "bald frequency")
410+
}
411+
412+
func TestNewClassifierTfIdfNotUnique(t *testing.T) {
413+
defer func() {
414+
if err := recover(); err != nil {
415+
// we are good
416+
}
417+
}()
418+
c := NewClassifierTfIdf(Good, Good, Bad)
419+
Assert(t, false, "should have panicked:", c)
420+
}
421+
422+
func TestNewClassifierTfIdfTooFew(t *testing.T) {
423+
defer func() {
424+
if err := recover(); err != nil {
425+
// we are good
426+
}
427+
}()
428+
c := NewClassifierTfIdf(Good)
429+
Assert(t, false, "should have panicked:", c)
430+
}
431+
432+
func TestTfIdfProbScoresPanic(t *testing.T) {
433+
c := NewClassifierTfIdf(Good, Bad)
434+
c.Learn([]string{"tall", "handsome"}, Good)
435+
436+
defer func() {
437+
if err := recover(); err != nil {
438+
// we are good - should panic without ConvertTermsFreqToTfIdf
439+
}
440+
}()
441+
c.ProbScores([]string{"tall"})
442+
Assert(t, false, "should have panicked")
443+
}
444+
445+
func TestTfIdfSafeProbScoresPanic(t *testing.T) {
446+
c := NewClassifierTfIdf(Good, Bad)
447+
c.Learn([]string{"tall", "handsome"}, Good)
448+
449+
defer func() {
450+
if err := recover(); err != nil {
451+
// we are good - should panic without ConvertTermsFreqToTfIdf
452+
}
453+
}()
454+
c.SafeProbScores([]string{"tall"})
455+
Assert(t, false, "should have panicked")
456+
}
457+
458+
func TestTfIdfLearnAfterConvertPanic(t *testing.T) {
459+
c := NewClassifierTfIdf(Good, Bad)
460+
c.Learn([]string{"tall", "handsome"}, Good)
461+
c.ConvertTermsFreqToTfIdf()
462+
463+
defer func() {
464+
if err := recover(); err != nil {
465+
// we are good - should panic when learning after conversion
466+
}
467+
}()
468+
c.Learn([]string{"more", "words"}, Good)
469+
Assert(t, false, "should have panicked")
470+
}
471+
472+
func TestNewClassifierFromFileError(t *testing.T) {
473+
_, err := NewClassifierFromFile("nonexistent_file.ser")
474+
Assert(t, err != nil, "should return error for nonexistent file")
475+
}
476+
477+
func TestWriteToFileError(t *testing.T) {
478+
c := NewClassifier(Good, Bad)
479+
c.Learn([]string{"test"}, Good)
480+
// Try to write to an invalid path
481+
err := c.WriteToFile("/nonexistent_directory/test.ser")
482+
Assert(t, err != nil, "should return error for invalid path")
483+
}
484+
485+
func TestWriteClassToFileError(t *testing.T) {
486+
c := NewClassifier(Good, Bad)
487+
c.Learn([]string{"test"}, Good)
488+
// Try to write to an invalid path
489+
err := c.WriteClassToFile(Good, "/nonexistent_directory")
490+
Assert(t, err != nil, "should return error for invalid path")
491+
}
492+
493+
func TestReadClassFromFileError(t *testing.T) {
494+
c := NewClassifier(Good, Bad)
495+
err := c.ReadClassFromFile(Good, "/nonexistent_directory")
496+
Assert(t, err != nil, "should return error for nonexistent file")
497+
}

0 commit comments

Comments
 (0)