sonar

Scan files at memory bandwidth speed.
Log | Files | Refs

tree_test.odin (4053B)


      1 package scan
      2 
      3 import "core:strings"
      4 import "core:testing"
      5 
      6 @(private = "file")
      7 fresh :: proc(t: ^testing.T, writers := 1) -> Tree {
      8 	tree: Tree
      9 	testing.expect_value(t, tree_init(&tree, writers), Error.None)
     10 	return tree
     11 }
     12 
     13 @(test)
     14 test_claim_hands_out_distinct_slots :: proc(t: ^testing.T) {
     15 	tree := fresh(t)
     16 	defer tree_destroy(&tree)
     17 	w := writer(&tree)
     18 
     19 	a, a_err := claim(&w, 3)
     20 	b, b_err := claim(&w, 2)
     21 	testing.expect_value(t, a_err, Error.None)
     22 	testing.expect_value(t, b_err, Error.None)
     23 	testing.expect_value(t, a, u32(0))
     24 	testing.expect_value(t, b, u32(3))
     25 	testing.expect_value(t, tree.count, u32(5))
     26 }
     27 
     28 @(test)
     29 test_claim_grows_across_blocks :: proc(t: ^testing.T) {
     30 	// Crossing a block boundary is where a growable store goes wrong, so write a
     31 	// marker either side of one and read both back.
     32 	tree := fresh(t)
     33 	defer tree_destroy(&tree)
     34 	w := writer(&tree)
     35 
     36 	first, err := claim(&w, BLOCK_NODES + 16)
     37 	testing.expect_value(t, err, Error.None)
     38 	testing.expect_value(t, first, u32(0))
     39 
     40 	node(&tree, 0).size = 11
     41 	node(&tree, BLOCK_NODES - 1).size = 22
     42 	node(&tree, BLOCK_NODES).size = 33
     43 	node(&tree, BLOCK_NODES + 15).size = 44
     44 
     45 	testing.expect_value(t, node(&tree, 0).size, u64(11))
     46 	testing.expect_value(t, node(&tree, BLOCK_NODES - 1).size, u64(22))
     47 	testing.expect_value(t, node(&tree, BLOCK_NODES).size, u64(33))
     48 	testing.expect_value(t, node(&tree, BLOCK_NODES + 15).size, u64(44))
     49 }
     50 
     51 @(test)
     52 test_reserve_makes_every_slot_addressable :: proc(t: ^testing.T) {
     53 	// A reader that indexes by its own numbering needs the whole range at once.
     54 	tree := fresh(t)
     55 	defer tree_destroy(&tree)
     56 	testing.expect_value(t, reserve(&tree, 100_000), Error.None)
     57 	testing.expect_value(t, tree.count, u32(100_000))
     58 	node(&tree, 99_999).size = 7
     59 	testing.expect_value(t, node(&tree, 99_999).size, u64(7))
     60 }
     61 
     62 @(test)
     63 test_interned_names_outlive_the_source :: proc(t: ^testing.T) {
     64 	tree := fresh(t)
     65 	defer tree_destroy(&tree)
     66 	w := writer(&tree)
     67 
     68 	buf := [8]byte{'r', 'e', 'p', 'o', 'r', 't', 0, 0}
     69 	name := intern(&w, string(buf[:6]))
     70 	buf = {'x', 'x', 'x', 'x', 'x', 'x', 0, 0} // the source is reused, as a read buffer is
     71 	testing.expect_value(t, name, "report")
     72 }
     73 
     74 @(test)
     75 test_path_walks_to_a_root :: proc(t: ^testing.T) {
     76 	tree := fresh(t)
     77 	defer tree_destroy(&tree)
     78 	w := writer(&tree)
     79 	first, _ := claim(&w, 3)
     80 	testing.expect_value(t, first, u32(0))
     81 
     82 	node(&tree, 0)^ = Node {
     83 		parent = 0,
     84 		name   = "C:",
     85 		flags  = {.Used, .Directory},
     86 	}
     87 	node(&tree, 1)^ = Node {
     88 		parent = 0,
     89 		name   = "Windows",
     90 		flags  = {.Used, .Directory},
     91 	}
     92 	node(&tree, 2)^ = Node {
     93 		parent = 1,
     94 		name   = "notepad.exe",
     95 		flags  = {.Used},
     96 	}
     97 
     98 	// Written with the separator of the machine showing the path, not the one the
     99 	// names came from, so this is built rather than spelled.
    100 	want := strings.concatenate(
    101 		{"C:", SEPARATOR, "Windows", SEPARATOR, "notepad.exe"},
    102 		context.temp_allocator,
    103 	)
    104 	testing.expect_value(t, path(&tree, 2, context.temp_allocator), want)
    105 	testing.expect_value(t, path(&tree, 0, context.temp_allocator), "C:")
    106 }
    107 
    108 @(test)
    109 test_path_stops_at_a_cycle :: proc(t: ^testing.T) {
    110 	// A corrupt source can name a parent that leads back round. The walk must end
    111 	// rather than run forever.
    112 	tree := fresh(t)
    113 	defer tree_destroy(&tree)
    114 	w := writer(&tree)
    115 	claim(&w, 2)
    116 	node(&tree, 0)^ = Node {
    117 		parent = 1,
    118 		name   = "a",
    119 		flags  = {.Used, .Directory},
    120 	}
    121 	node(&tree, 1)^ = Node {
    122 		parent = 0,
    123 		name   = "b",
    124 		flags  = {.Used, .Directory},
    125 	}
    126 
    127 	p := path(&tree, 0, context.temp_allocator)
    128 	testing.expect(t, len(p) > 0, "a cycle produced no path at all")
    129 }
    130 
    131 @(test)
    132 test_cancel_is_visible_to_a_reader :: proc(t: ^testing.T) {
    133 	tree := fresh(t)
    134 	defer tree_destroy(&tree)
    135 	testing.expect(t, !cancelled(&tree))
    136 	cancel(&tree)
    137 	testing.expect(t, cancelled(&tree))
    138 }
    139 
    140 @(test)
    141 test_progress_accumulates :: proc(t: ^testing.T) {
    142 	tree := fresh(t)
    143 	defer tree_destroy(&tree)
    144 	progress(&tree, 3, 300)
    145 	progress(&tree, 4, 400)
    146 	testing.expect_value(t, tree.nodes_done, u64(7))
    147 	testing.expect_value(t, tree.bytes_done, u64(700))
    148 }