8.5 KB214 lines
Blame
1import { describe, expect, it } from 'vitest';
2import type { Branch, Merge } from '../src/language/index.js';
3import { gitGraphParse as parse } from './test-util.js';
4import type { Commit } from '../src/language/index.js';
5import type { Checkout, CherryPicking } from '../src/language/generated/ast.js';
6
7describe('Parsing Commit Statements', () => {
8 it('should parse a simple commit', () => {
9 const result = parse(`gitGraph\n commit\n`);
10 expect(result.value.statements[0].$type).toBe('Commit');
11 });
12
13 it('should parse multiple commits', () => {
14 const result = parse(`gitGraph\n commit\n commit\n commit\n`);
15 expect(result.value.statements).toHaveLength(3);
16 });
17
18 it('should parse commits with all properties', () => {
19 const result = parse(`gitGraph\n commit id:"1" msg:"Fix bug" tag:"v1.2" type:NORMAL\n`);
20 const commit = result.value.statements[0] as Commit;
21 expect(commit.$type).toBe('Commit');
22 expect(commit.id).toBe('1');
23 expect(commit.message).toBe('Fix bug');
24 expect(commit.tags).toEqual(['v1.2']);
25 expect(commit.type).toBe('NORMAL');
26 });
27
28 it('should handle commit messages with special characters', () => {
29 const result = parse(`gitGraph\n commit msg:"Fix issue #123: Handle errors"\n`);
30 const commit = result.value.statements[0] as Commit;
31 expect(commit.message).toBe('Fix issue #123: Handle errors');
32 });
33
34 it('should parse commits with only a message and no other properties', () => {
35 const result = parse(`gitGraph\n commit msg:"Initial release"\n`);
36 const commit = result.value.statements[0] as Commit;
37 expect(commit.message).toBe('Initial release');
38 expect(commit.id).toBeUndefined();
39 expect(commit.type).toBeUndefined();
40 });
41
42 it('should ignore malformed properties and not break parsing', () => {
43 const result = parse(`gitGraph\n commit id:"2" msg:"Malformed commit" oops:"ignored"\n`);
44 const commit = result.value.statements[0] as Commit;
45 expect(commit.id).toBe('2');
46 expect(commit.message).toBe('Malformed commit');
47 expect(commit.hasOwnProperty('oops')).toBe(false);
48 });
49
50 it('should parse multiple commits with different types', () => {
51 const result = parse(`gitGraph\n commit type:NORMAL\n commit type:REVERSE\n`);
52 const commit1 = result.value.statements[0] as Commit;
53 const commit2 = result.value.statements[1] as Commit;
54 expect(commit1.type).toBe('NORMAL');
55 expect(commit2.type).toBe('REVERSE');
56 });
57});
58
59describe('Parsing Branch Statements', () => {
60 it('should parse a branch with a simple name', () => {
61 const result = parse(`gitGraph\n commit\n commit\n branch master\n`);
62 const branch = result.value.statements[2] as Branch;
63 expect(branch.name).toBe('master');
64 });
65
66 it('should parse a branch name starting with numbers', () => {
67 const result = parse(`gitGraph\n commit\n branch 1.0.1\n`);
68 const branch = result.value.statements[1] as Branch;
69 expect(branch.name).toBe('1.0.1');
70 });
71
72 it('should parse a branch with an order property', () => {
73 const result = parse(`gitGraph\n commit\n branch feature order:1\n`);
74 const branch = result.value.statements[1] as Branch;
75 expect(branch.name).toBe('feature');
76 expect(branch.order).toBe(1);
77 });
78
79 it('should handle branch names with special characters', () => {
80 const result = parse(`gitGraph\n branch feature/test-branch\n`);
81 const branch = result.value.statements[0] as Branch;
82 expect(branch.name).toBe('feature/test-branch');
83 });
84
85 it('should parse branches with hyphens and underscores', () => {
86 const result = parse(`gitGraph\n branch my-feature_branch\n`);
87 const branch = result.value.statements[0] as Branch;
88 expect(branch.name).toBe('my-feature_branch');
89 });
90
91 it('should correctly handle branch without order property', () => {
92 const result = parse(`gitGraph\n branch feature\n`);
93 const branch = result.value.statements[0] as Branch;
94 expect(branch.name).toBe('feature');
95 expect(branch.order).toBeUndefined();
96 });
97});
98
99describe('Parsing Merge Statements', () => {
100 it('should parse a merge with a branch name', () => {
101 const result = parse(`gitGraph\n merge master\n`);
102 const merge = result.value.statements[0] as Merge;
103 expect(merge.branch).toBe('master');
104 });
105
106 it('should handle merges with additional properties', () => {
107 const result = parse(`gitGraph\n merge feature id:"m1" tag:"release" type:HIGHLIGHT\n`);
108 const merge = result.value.statements[0] as Merge;
109 expect(merge.branch).toBe('feature');
110 expect(merge.id).toBe('m1');
111 expect(merge.tags).toEqual(['release']);
112 expect(merge.type).toBe('HIGHLIGHT');
113 });
114
115 it('should parse merge without any properties', () => {
116 const result = parse(`gitGraph\n merge feature\n`);
117 const merge = result.value.statements[0] as Merge;
118 expect(merge.branch).toBe('feature');
119 });
120
121 it('should ignore malformed properties in merge statements', () => {
122 const result = parse(`gitGraph\n merge feature random:"ignored"\n`);
123 const merge = result.value.statements[0] as Merge;
124 expect(merge.branch).toBe('feature');
125 expect(merge.hasOwnProperty('random')).toBe(false);
126 });
127});
128
129describe('Parsing Checkout Statements', () => {
130 it('should parse a checkout to a named branch', () => {
131 const result = parse(
132 `gitGraph\n commit id:"1"\n branch develop\n branch fun\n checkout develop\n`
133 );
134 const checkout = result.value.statements[3] as Checkout;
135 expect(checkout.branch).toBe('develop');
136 });
137
138 it('should parse checkout to branches with complex names', () => {
139 const result = parse(`gitGraph\n checkout hotfix-123\n`);
140 const checkout = result.value.statements[0] as Checkout;
141 expect(checkout.branch).toBe('hotfix-123');
142 });
143
144 it('should parse checkouts with hyphens and numbers', () => {
145 const result = parse(`gitGraph\n checkout release-2021\n`);
146 const checkout = result.value.statements[0] as Checkout;
147 expect(checkout.branch).toBe('release-2021');
148 });
149});
150
151describe('Parsing CherryPicking Statements', () => {
152 it('should parse cherry-picking with a commit id', () => {
153 const result = parse(`gitGraph\n commit id:"123" commit id:"321" cherry-pick id:"123"\n`);
154 const cherryPick = result.value.statements[2] as CherryPicking;
155 expect(cherryPick.id).toBe('123');
156 });
157
158 it('should parse cherry-picking with multiple properties', () => {
159 const result = parse(`gitGraph\n cherry-pick id:"123" tag:"urgent" parent:"100"\n`);
160 const cherryPick = result.value.statements[0] as CherryPicking;
161 expect(cherryPick.id).toBe('123');
162 expect(cherryPick.tags).toEqual(['urgent']);
163 expect(cherryPick.parent).toBe('100');
164 });
165
166 describe('Parsing with Accessibility Titles and Descriptions', () => {
167 it('should parse accessibility titles', () => {
168 const result = parse(`gitGraph\n accTitle: Accessible Graph\n commit\n`);
169 expect(result.value.accTitle).toBe('Accessible Graph');
170 });
171
172 it('should parse multiline accessibility descriptions', () => {
173 const result = parse(
174 `gitGraph\n accDescr {\n Detailed description\n across multiple lines\n }\n commit\n`
175 );
176 expect(result.value.accDescr).toBe('Detailed description\nacross multiple lines');
177 });
178 });
179
180 describe('Integration Tests', () => {
181 it('should correctly parse a complex graph with various elements', () => {
182 const result = parse(`
183 gitGraph TB:
184 accTitle: Complex Example
185 commit id:"init" type:NORMAL
186 branch feature
187 commit id:"feat1" msg:"Add feature"
188 checkout main
189 merge feature tag:"v1.0"
190 cherry-pick id:"feat1" tag:"critical fix"
191 `);
192 expect(result.value.accTitle).toBe('Complex Example');
193 expect(result.value.statements[0].$type).toBe('Commit');
194 expect(result.value.statements[1].$type).toBe('Branch');
195 expect(result.value.statements[2].$type).toBe('Commit');
196 expect(result.value.statements[3].$type).toBe('Checkout');
197 expect(result.value.statements[4].$type).toBe('Merge');
198 expect(result.value.statements[5].$type).toBe('CherryPicking');
199 });
200 });
201
202 describe('Error Handling for Invalid Syntax', () => {
203 it('should report errors for unknown properties in commit', () => {
204 const result = parse(`gitGraph\n commit unknown:"oops"\n`);
205 expect(result.parserErrors).not.toHaveLength(0);
206 });
207
208 it('should report errors for invalid branch order', () => {
209 const result = parse(`gitGraph\n branch feature order:xyz\n`);
210 expect(result.parserErrors).not.toHaveLength(0);
211 });
212 });
213});
214