v / vlib / v2 / ast / flat_replace_file_stmt_test.v
153 lines · 142 sloc · 3.93 KB · f3c5760b8838272e4789c38a1be9e03f9ceac351
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module ast
5
6// Tests for `FlatBuilder.replace_file_stmt`. The companion primitive to
7// `prepend_to_fn_body`: when a caller swaps a stmt for a re-emitted variant
8// (e.g. the new FnDecl returned by `prepend_to_fn_body`), `replace_file_stmt`
9// rebuilds the enclosing file root so the file's stmts list references the
10// new id. Together they support the prepend-style post_pass mutations
11// (`inject_main_runtime_const_init_calls`, s155).
12
13fn make_minimal_file_with_three_consts() File {
14 return File{
15 name: 'inline.v'
16 mod: 'foo'
17 stmts: [
18 Stmt(ModuleStmt{
19 name: 'foo'
20 }),
21 Stmt(ConstDecl{
22 fields: [
23 FieldInit{
24 name: 'A'
25 value: Expr(BasicLiteral{
26 kind: .number
27 value: '1'
28 })
29 },
30 ]
31 }),
32 Stmt(ConstDecl{
33 fields: [
34 FieldInit{
35 name: 'B'
36 value: Expr(BasicLiteral{
37 kind: .number
38 value: '2'
39 })
40 },
41 ]
42 }),
43 Stmt(ConstDecl{
44 fields: [
45 FieldInit{
46 name: 'C'
47 value: Expr(BasicLiteral{
48 kind: .number
49 value: '3'
50 })
51 },
52 ]
53 }),
54 ]
55 }
56}
57
58fn make_replacement_const_stmt() Stmt {
59 return Stmt(ConstDecl{
60 fields: [
61 FieldInit{
62 name: 'Z'
63 value: Expr(BasicLiteral{
64 kind: .number
65 value: '99'
66 })
67 },
68 ]
69 })
70}
71
72fn make_const_stmt_named(name string, value string) Stmt {
73 return Stmt(ConstDecl{
74 fields: [
75 FieldInit{
76 name: name
77 value: Expr(BasicLiteral{
78 kind: .number
79 value: value
80 })
81 },
82 ]
83 })
84}
85
86// Reference: build the file with stmt index 2 (the `B` const) already
87// replaced by the `Z` const at construction time.
88fn build_reference_with_replacement() FlatAst {
89 mut b := new_flat_builder()
90 b.append_file(File{
91 name: 'inline.v'
92 mod: 'foo'
93 stmts: [
94 Stmt(ModuleStmt{
95 name: 'foo'
96 }),
97 make_const_stmt_named('A', '1'),
98 make_replacement_const_stmt(),
99 make_const_stmt_named('C', '3'),
100 ]
101 })
102 return b.flat
103}
104
105// Subject: build the bare three-const file, emit the replacement stmt
106// separately, then splice it in via `replace_file_stmt(0, 2, z_id)`.
107fn build_subject_with_replacement() FlatAst {
108 mut b := new_flat_builder()
109 b.append_file(make_minimal_file_with_three_consts())
110 z_id := b.emit_stmt(make_replacement_const_stmt())
111 b.replace_file_stmt(0, 2, z_id)
112 return b.flat
113}
114
115fn test_replace_file_stmt_signature_matches_reference() {
116 ref_sig := build_reference_with_replacement().signature()
117 sub_sig := build_subject_with_replacement().signature()
118 assert ref_sig == sub_sig
119}
120
121fn test_replace_file_stmt_invalid_file_idx_returns_invalid() {
122 mut b := new_flat_builder()
123 b.append_file(make_minimal_file_with_three_consts())
124 z_id := b.emit_stmt(make_replacement_const_stmt())
125 returned_id := b.replace_file_stmt(-1, 0, z_id)
126 assert returned_id == invalid_flat_node_id
127}
128
129fn test_replace_file_stmt_invalid_stmt_idx_returns_invalid() {
130 mut b := new_flat_builder()
131 b.append_file(make_minimal_file_with_three_consts())
132 z_id := b.emit_stmt(make_replacement_const_stmt())
133 // File has 4 stmts (module + 3 consts); idx 99 is out of range.
134 returned_id := b.replace_file_stmt(0, 99, z_id)
135 assert returned_id == invalid_flat_node_id
136}
137
138fn test_replace_file_stmt_invalid_new_id_returns_invalid() {
139 mut b := new_flat_builder()
140 b.append_file(make_minimal_file_with_three_consts())
141 returned_id := b.replace_file_stmt(0, 0, FlatNodeId(-1))
142 assert returned_id == invalid_flat_node_id
143}
144
145fn test_replace_file_stmt_updates_files_table() {
146 mut b := new_flat_builder()
147 original_file_id := b.append_file(make_minimal_file_with_three_consts())
148 z_id := b.emit_stmt(make_replacement_const_stmt())
149 new_file_id := b.replace_file_stmt(0, 1, z_id)
150 // The flat.files[0].file_id must point at the new file root, not the old.
151 assert new_file_id != original_file_id
152 assert b.flat.files[0].file_id == new_file_id
153}
154