review

review patchsets using your default editor
Log | Files | Refs

finding_test.odin (6772B)


      1 package finding
      2 
      3 import "core:os"
      4 import "core:path/filepath"
      5 import "core:strings"
      6 import "core:testing"
      7 
      8 @(test)
      9 severity_round_trips :: proc(t: ^testing.T) {
     10 	testing.expect_value(t, parse_severity(" Must-Fix "), Severity.Must_Fix)
     11 	testing.expect_value(t, parse_severity("error"), Severity.Must_Fix)
     12 	testing.expect_value(t, parse_severity("warning"), Severity.Consider)
     13 	testing.expect_value(t, parse_severity("whatever"), Severity.Note)
     14 	testing.expect_value(t, severity_name(.Consider), "consider")
     15 }
     16 
     17 @(test)
     18 to_string_says_where_and_what :: proc(t: ^testing.T) {
     19 	s := to_string(
     20 		Finding {
     21 			job = "tests",
     22 			rule = "cannot-fail",
     23 			severity = .Must_Fix,
     24 			file = "a_test.go",
     25 			line = 4,
     26 			message = "m",
     27 			fix = "do x",
     28 		},
     29 		context.temp_allocator,
     30 	)
     31 	testing.expect_value(
     32 		t,
     33 		s,
     34 		"must-fix: a_test.go:4: m\n      → do x\n      [tests/cannot-fail]",
     35 	)
     36 	s = to_string(
     37 		Finding {
     38 			job = "namer",
     39 			rule = "abbreviation",
     40 			severity = .Note,
     41 			symbol = "cfg",
     42 			message = "m",
     43 		},
     44 		context.temp_allocator,
     45 	)
     46 	testing.expect_value(t, s, "note: cfg: m\n      [namer/abbreviation]")
     47 }
     48 
     49 @(test)
     50 sort_puts_the_serious_first :: proc(t: ^testing.T) {
     51 	findings := []Finding {
     52 		{severity = .Note, file = "b.go", line = 1},
     53 		{severity = .Must_Fix, file = "b.go", line = 9},
     54 		{severity = .Must_Fix, file = "a.go", line = 2},
     55 		{severity = .Must_Fix, file = "a.go", line = 1},
     56 	}
     57 	sort(findings)
     58 	testing.expect_value(t, findings[0].file, "a.go")
     59 	testing.expect_value(t, findings[0].line, 1)
     60 	testing.expect_value(t, findings[1].line, 2)
     61 	testing.expect_value(t, findings[2].line, 9)
     62 	testing.expect_value(t, findings[3].severity, Severity.Note)
     63 	testing.expect(t, must_fix(findings))
     64 	testing.expect(t, !must_fix(findings[3:]))
     65 }
     66 
     67 @(test)
     68 id_is_stable_and_matches_the_go_tool :: proc(t: ^testing.T) {
     69 	f := Finding {
     70 		job     = "tests",
     71 		rule    = "cannot-fail",
     72 		file    = "x_test.go",
     73 		line    = 4,
     74 		symbol  = "TestX",
     75 		message = "m",
     76 	}
     77 	identify(&f, context.temp_allocator)
     78 	// sha256("tests\x00cannot-fail\x00x_test.go\x00TestX")[:12], as Go names it.
     79 	testing.expect_value(t, f.id, "52ef4321ce06")
     80 	moved := f
     81 	moved.line = 9
     82 	identify(&moved, context.temp_allocator)
     83 	testing.expect_value(t, moved.id, f.id)
     84 	reworded := f
     85 	reworded.message = "said another way"
     86 	identify(&reworded, context.temp_allocator)
     87 	testing.expect_value(t, reworded.id, f.id)
     88 	other := f
     89 	other.symbol = "TestY"
     90 	identify(&other, context.temp_allocator)
     91 	testing.expect(t, other.id != f.id, "two findings share one id")
     92 
     93 	a := Finding {
     94 		job  = "claims",
     95 		rule = "unsupported-claim",
     96 		file = "x.go",
     97 		line = 4,
     98 	}
     99 	b := Finding {
    100 		job  = "claims",
    101 		rule = "unsupported-claim",
    102 		file = "x.go",
    103 		line = 9,
    104 	}
    105 	identify(&a, context.temp_allocator)
    106 	identify(&b, context.temp_allocator)
    107 	testing.expect(t, a.id != b.id, "two comments share one id")
    108 
    109 	s1 := Finding {
    110 		job     = "static",
    111 		rule    = "history-coupled-file",
    112 		file    = "a.go",
    113 		message = "ties a.go to b.go",
    114 	}
    115 	s2 := Finding {
    116 		job     = "static",
    117 		rule    = "history-coupled-file",
    118 		file    = "a.go",
    119 		message = "ties a.go to c.go",
    120 	}
    121 	identify(&s1, context.temp_allocator)
    122 	identify(&s2, context.temp_allocator)
    123 	testing.expect(t, s1.id != s2.id, "two partners share one id")
    124 }
    125 
    126 @(test)
    127 name_tells_twins_apart :: proc(t: ^testing.T) {
    128 	findings := []Finding {
    129 		{job = "namer", rule = "abbreviation", file = "x.go", symbol = "cfg", severity = .Note},
    130 		{job = "namer", rule = "abbreviation", file = "x.go", symbol = "cfg", severity = .Note},
    131 	}
    132 	name(findings, context.temp_allocator)
    133 	testing.expect(t, findings[0].id != findings[1].id)
    134 	testing.expect(t, strings.has_suffix(findings[1].id, "-2"))
    135 	testing.expect_value(t, findings[0].severity_name, "note")
    136 }
    137 
    138 write_source :: proc(t: ^testing.T, name, src: string) -> (dir: string) {
    139 	temp := os.temp_directory(context.temp_allocator) or_else ""
    140 	scratch, err := os.make_directory_temp(temp, "review-finding-*", context.temp_allocator)
    141 	if err != nil {
    142 		testing.fail_now(t, "no scratch directory")
    143 	}
    144 	path := filepath.join({scratch, name}, context.temp_allocator) or_else name
    145 	testing.expect(t, os.write_entire_file(path, transmute([]byte)src) == nil)
    146 	return scratch
    147 }
    148 
    149 @(test)
    150 suppressed_reads_the_dismissal_beside_the_line :: proc(t: ^testing.T) {
    151 	dir := write_source(
    152 		t,
    153 		"x.go",
    154 		"package x\n\n// nothing here\nconst a = 1\n\n//review:" +
    155 		"ignore restates-a-fact the ico package owns the other one\nconst b = 6\n\nconst c = 7\n\nconst d = 8\n\nconst e = 9\n",
    156 	)
    157 	defer os.remove_all(dir)
    158 	Case :: struct {
    159 		name: string,
    160 		f:    Finding,
    161 		want: bool,
    162 		why:  string,
    163 	}
    164 	for c in ([]Case{{"just above", {file = "x.go", line = 7, rule = "restates-a-fact"}, true, "the ico package owns the other one"}, {"on the line", {file = "x.go", line = 6, rule = "restates-a-fact"}, true, "the ico package owns the other one"}, {"distant", {file = "x.go", line = 12, rule = "restates-a-fact"}, false, ""}, {"another rule", {file = "x.go", line = 7, rule = "already-named"}, false, ""}, {"no line", {file = "x.go", rule = "restates-a-fact"}, true, "the ico package owns the other one"}, {"no file", {rule = "restates-a-fact"}, false, ""}, {"missing file", {file = "nowhere.go", line = 1, rule = "restates-a-fact"}, false, ""}}) {
    165 		why, ok := suppressed(c.f, dir, context.temp_allocator)
    166 		testing.expectf(t, ok == c.want, "%s: got %v, want %v", c.name, ok, c.want)
    167 		if ok {
    168 			testing.expectf(t, why == c.why, "%s: reason %q", c.name, why)
    169 		}
    170 	}
    171 }
    172 
    173 @(test)
    174 suppressed_reads_all_and_no_reason :: proc(t: ^testing.T) {
    175 	dir := write_source(t, "x.go", "//review:" + "ignore all generated\nconst a = 1\n")
    176 	defer os.remove_all(dir)
    177 	why, ok := suppressed(
    178 		Finding{file = "x.go", line = 2, rule = "anything-at-all"},
    179 		dir,
    180 		context.temp_allocator,
    181 	)
    182 	testing.expect(t, ok)
    183 	testing.expect_value(t, why, "generated")
    184 	other := write_source(
    185 		t,
    186 		"y.go",
    187 		"// review:" + "ignore cannot-fail\nfunc TestX(t *testing.T) {}\n",
    188 	)
    189 	defer os.remove_all(other)
    190 	why, ok = suppressed(
    191 		Finding{file = "y.go", line = 2, rule = "cannot-fail"},
    192 		other,
    193 		context.temp_allocator,
    194 	)
    195 	testing.expect(t, ok, "a space after the slashes still dismisses")
    196 	testing.expect_value(t, why, "no reason given")
    197 }
    198 
    199 @(test)
    200 dismissal_needs_the_slashes :: proc(t: ^testing.T) {
    201 	rule, why, found := dismissal("x := 1 //review:" + "ignore no-shadow it is the loop's")
    202 	testing.expect(t, found)
    203 	testing.expect_value(t, rule, "no-shadow")
    204 	testing.expect_value(t, why, "it is the loop's")
    205 	_, _, found = dismissal("review:ignore no-shadow prose")
    206 	testing.expect(t, !found)
    207 	_, _, found = dismissal("//review:" + "ignore")
    208 	testing.expect(t, !found)
    209 	testing.expect_value(t, atoi(" 42 "), 42)
    210 	testing.expect_value(t, atoi("x"), 0)
    211 }