review

review patchsets using your default editor
Log | Files | Refs

frontend_test.odin (7406B)


      1 package frontend
      2 
      3 import "core:os"
      4 import "core:path/filepath"
      5 import "core:testing"
      6 
      7 write_temp :: proc(t: ^testing.T, name, src: string) -> string {
      8 	dir, err := os.temp_directory(context.temp_allocator)
      9 	testing.expect(t, err == nil, "temp directory")
     10 	path, join_err := filepath.join({dir, name}, context.temp_allocator)
     11 	testing.expect(t, join_err == nil, "join")
     12 	testing.expect(t, os.write_entire_file(path, transmute([]byte)src) == nil, "write fixture")
     13 	return path
     14 }
     15 
     16 @(test)
     17 go_sidecar_lists_declarations :: proc(t: ^testing.T) {
     18 	if !installed(.Go) {
     19 		testing.fail_now(
     20 			t,
     21 			"review-go is not on the path: go build -o ~/go/bin/review-go ./sidecar/gofront",
     22 		)
     23 	}
     24 	path := write_temp(
     25 		t,
     26 		"review_frontend_fixture.go",
     27 		`package fixture
     28 
     29 import "fmt"
     30 
     31 // Limit bounds the work.
     32 const Limit = 3
     33 
     34 type Point struct{ X int }
     35 
     36 func helper() { fmt.Println(Limit) }
     37 
     38 func TestHelper(t *testing.T) { helper() }
     39 `,
     40 	)
     41 	defer os.remove(path)
     42 
     43 	out, err := scan(.Go, {path}, context.temp_allocator)
     44 	testing.expect_value(t, err, Scan_Error.None)
     45 	testing.expect_value(t, len(out.files), 1)
     46 	file := out.files[0]
     47 	testing.expect_value(t, file.name, path)
     48 	testing.expect_value(t, file.pkg, "fixture")
     49 	testing.expect_value(t, file.error, "")
     50 	testing.expect_value(t, len(file.imports), 1)
     51 	testing.expect_value(t, file.imports[0], "fmt")
     52 
     53 	by_name := make(map[string]Decl, context.temp_allocator)
     54 	for decl in file.decls {
     55 		by_name[decl.name] = decl
     56 	}
     57 	testing.expect_value(t, len(by_name), 5)
     58 	testing.expect_value(t, by_name["Limit"].kind, "const")
     59 	testing.expect_value(t, by_name["Limit"].line, 6)
     60 	testing.expect_value(t, by_name["Limit"].doc, "Limit bounds the work.")
     61 	testing.expect_value(t, by_name["Limit"].exported, true)
     62 	testing.expect_value(t, by_name["Point"].kind, "type")
     63 	testing.expect_value(t, by_name["X"].kind, "field")
     64 	testing.expect_value(t, by_name["helper"].exported, false)
     65 	testing.expect_value(t, by_name["helper"].text, "func helper() { fmt.Println(Limit) }")
     66 	testing.expect_value(t, by_name["TestHelper"].test, true)
     67 
     68 	found := tests(file, context.temp_allocator)
     69 	testing.expect_value(t, len(found), 1)
     70 	testing.expect_value(t, found[0].name, "TestHelper")
     71 	testing.expect_value(t, len(file.comments), 1)
     72 	testing.expect_value(t, file.comments[0].line, 5)
     73 }
     74 
     75 @(test)
     76 go_sidecar_reports_a_file_it_cannot_parse :: proc(t: ^testing.T) {
     77 	if !installed(.Go) {
     78 		testing.fail_now(t, "review-go is not on the path")
     79 	}
     80 	path := write_temp(t, "review_frontend_broken.go", "package x\nfunc {\n")
     81 	defer os.remove(path)
     82 	out, err := scan(.Go, {path}, context.temp_allocator)
     83 	testing.expect_value(t, err, Scan_Error.None)
     84 	testing.expect_value(t, len(out.files), 1)
     85 	testing.expect(t, len(out.files[0].error) > 0, "a parse error is reported")
     86 	testing.expect_value(t, len(out.files[0].decls), 0)
     87 }
     88 
     89 @(test)
     90 scan_of_nothing_asks_nothing :: proc(t: ^testing.T) {
     91 	out, err := scan(.Go, {}, context.temp_allocator)
     92 	testing.expect_value(t, err, Scan_Error.None)
     93 	testing.expect_value(t, len(out.files), 0)
     94 }
     95 
     96 write_fixture :: proc(t: ^testing.T, name, src: string) -> string {
     97 	return write_temp(t, name, src)
     98 }
     99 
    100 @(test)
    101 ast_grep_reads_typescript :: proc(t: ^testing.T) {
    102 	if !installed(.Script) {
    103 		testing.fail_now(t, "ast-grep is not on the path")
    104 	}
    105 	path := write_fixture(
    106 		t,
    107 		"review_grep_fixture.ts",
    108 		`import { x } from "y";
    109 
    110 // Limit bounds the work.
    111 export const limit: number = 3;
    112 const hidden = 4;
    113 export type Pair = [number, number];
    114 interface Shape { size: number }
    115 export function read(a: string): number {
    116   const inner = 1;
    117   return inner;
    118 }
    119 export default function main() {}
    120 describe('icons', () => {
    121   it('decodes the largest', () => { expect(size).toBe(1); });
    122   test.skip("reads a binary", () => {});
    123 });
    124 `,
    125 	)
    126 	defer os.remove(path)
    127 	out, err := scan(.Script, {path}, context.temp_allocator)
    128 	testing.expect_value(t, err, Scan_Error.None)
    129 	testing.expect_value(t, len(out.files), 1)
    130 	by := make(map[string]Decl, context.temp_allocator)
    131 	for d in out.files[0].decls {
    132 		by[d.name] = d
    133 	}
    134 	testing.expect_value(t, len(by), 8)
    135 	testing.expect_value(t, by["limit"].kind, "value")
    136 	testing.expect(t, by["limit"].exported)
    137 	testing.expect_value(t, by["limit"].doc, "Limit bounds the work.")
    138 	testing.expect_value(t, by["limit"].line, 4)
    139 	testing.expect(t, !by["hidden"].exported)
    140 	testing.expect_value(t, by["Pair"].kind, "type")
    141 	testing.expect_value(t, by["Shape"].kind, "type")
    142 	testing.expect_value(t, by["read"].kind, "func")
    143 	testing.expect_value(t, by["read"].end_line, 11)
    144 	testing.expect_value(t, by["main"].kind, "func")
    145 	testing.expect(t, by["decodes the largest"].test)
    146 	testing.expect(t, by["reads a binary"].test)
    147 	_, nested := by["inner"]
    148 	testing.expect(t, !nested, "a declaration inside a body is not top level")
    149 }
    150 
    151 @(test)
    152 ast_grep_reads_python_and_rust :: proc(t: ^testing.T) {
    153 	if !installed(.Python) {
    154 		testing.fail_now(t, "ast-grep is not on the path")
    155 	}
    156 	py := write_fixture(
    157 		t,
    158 		"review_grep_fixture.py",
    159 		`"""Icons."""
    160 MAX_ICONS = 12
    161 _hidden: int = 4
    162 
    163 # Reads the icons a file holds.
    164 def read_icons(src):
    165     inner = 1
    166     def nested():
    167         return inner
    168     return []
    169 
    170 class Reader:
    171     size = 0
    172     def method(self):
    173         return 1
    174 
    175 def test_smoke():
    176     read_icons("y")
    177 `,
    178 	)
    179 	defer os.remove(py)
    180 	out, err := scan(.Python, {py}, context.temp_allocator)
    181 	testing.expect_value(t, err, Scan_Error.None)
    182 	by := make(map[string]Decl, context.temp_allocator)
    183 	for d in out.files[0].decls {
    184 		by[d.name] = d
    185 	}
    186 	testing.expect_value(t, len(by), 5)
    187 	testing.expect_value(t, by["MAX_ICONS"].kind, "value")
    188 	testing.expect(t, by["MAX_ICONS"].exported)
    189 	testing.expect(t, !by["_hidden"].exported)
    190 	testing.expect_value(t, by["read_icons"].kind, "func")
    191 	testing.expect_value(t, by["read_icons"].doc, "Reads the icons a file holds.")
    192 	testing.expect_value(t, by["Reader"].kind, "type")
    193 	testing.expect(t, by["test_smoke"].test)
    194 	testing.expect_value(t, by["test_smoke"].kind, "func")
    195 
    196 	rs := write_fixture(
    197 		t,
    198 		"review_grep_fixture.rs",
    199 		`pub const LIMIT: usize = 3;
    200 static mut COUNT: i32 = 0;
    201 
    202 /// A shape.
    203 pub struct Shape { size: usize }
    204 
    205 impl Shape {
    206     pub fn area(&self) -> usize { self.size }
    207     fn hidden(&self) -> usize { 0 }
    208 }
    209 
    210 #[test]
    211 fn reads_shapes() {
    212     assert_eq!(count(), 1);
    213 }
    214 `,
    215 	)
    216 	defer os.remove(rs)
    217 	out, err = scan(.Rust, {rs}, context.temp_allocator)
    218 	testing.expect_value(t, err, Scan_Error.None)
    219 	clear(&by)
    220 	for d in out.files[0].decls {
    221 		by[d.name] = d
    222 	}
    223 	testing.expect_value(t, len(by), 6)
    224 	testing.expect(t, by["LIMIT"].exported)
    225 	testing.expect(t, !by["COUNT"].exported)
    226 	testing.expect_value(t, by["Shape"].kind, "type")
    227 	testing.expect_value(t, by["Shape"].doc, "A shape.")
    228 	testing.expect(t, by["area"].exported)
    229 	testing.expect(t, !by["hidden"].exported)
    230 	testing.expect(t, by["reads_shapes"].test)
    231 	testing.expect_value(t, by["reads_shapes"].end_line, 15)
    232 }
    233 
    234 @(test)
    235 doc_above_reads_the_block :: proc(t: ^testing.T) {
    236 	lines := []string{"x", "/** Two", " * lines */", "// and one", "const a = 1"}
    237 	testing.expect_value(t, doc_above(lines, 5, context.temp_allocator), "Two lines and one")
    238 	testing.expect_value(t, doc_above(lines, 1, context.temp_allocator), "")
    239 	testing.expect_value(t, scratch_ext("a/b.mjs"), ".js")
    240 	testing.expect_value(t, grammar_of("a.tsx"), "tsx")
    241 	testing.expect(t, typed("export type $N = $$$B"))
    242 	testing.expect(t, !typed("export const $N = $$$V"))
    243 }