1+ import { buildCommitDict , getLeafNodes , isLeafNode } from "./commit.util" ;
2+ import type { CommitDict , CommitRaw } from "./types" ;
3+
4+ describe ( "getLeafNodes" , ( ) => {
5+ const createMockCommitRaw = (
6+ id : string ,
7+ branches : string [ ] = [ ] ,
8+ overrides : Partial < CommitRaw > = { }
9+ ) : CommitRaw => ( {
10+ sequence : 1 ,
11+ id,
12+ parents : [ ] ,
13+ branches,
14+ tags : [ ] ,
15+ author : { name : "Test Author" , email : "test@example.com" } ,
16+ authorDate : new Date ( "2023-01-01" ) ,
17+ committer : { name : "Test Committer" , email : "test@example.com" } ,
18+ committerDate : new Date ( "2023-01-01" ) ,
19+ message : "Test commit message" ,
20+ differenceStatistic : {
21+ totalInsertionCount : 0 ,
22+ totalDeletionCount : 0 ,
23+ fileDictionary : { } ,
24+ } ,
25+ commitMessageType : "" ,
26+ ...overrides ,
27+ } ) ;
28+
29+ describe ( "normal cases" , ( ) => {
30+ it ( "should return nodes with branches as leaf nodes" , ( ) => {
31+ const commits : CommitRaw [ ] = [
32+ createMockCommitRaw ( "commit1" , [ "main" ] ) ,
33+ createMockCommitRaw ( "commit2" , [ "develop" ] ) ,
34+ createMockCommitRaw ( "commit3" , [ "feature/test" ] ) ,
35+ ] ;
36+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
37+
38+ const leafNodes = getLeafNodes ( commitDict ) ;
39+
40+ expect ( leafNodes ) . toHaveLength ( 3 ) ;
41+ expect ( leafNodes . map ( node => node . commit . id ) ) . toEqual (
42+ expect . arrayContaining ( [ "commit1" , "commit2" , "commit3" ] )
43+ ) ;
44+ } ) ;
45+
46+ it ( "should return nodes with multiple branches as leaf nodes" , ( ) => {
47+ const commits : CommitRaw [ ] = [
48+ createMockCommitRaw ( "commit1" , [ "main" , "develop" ] ) ,
49+ ] ;
50+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
51+
52+ const leafNodes = getLeafNodes ( commitDict ) ;
53+
54+ expect ( leafNodes ) . toHaveLength ( 1 ) ;
55+ expect ( leafNodes [ 0 ] . commit . id ) . toBe ( "commit1" ) ;
56+ expect ( leafNodes [ 0 ] . commit . branches ) . toEqual ( [ "main" , "develop" ] ) ;
57+ } ) ;
58+ } ) ;
59+
60+ describe ( "edge cases" , ( ) => {
61+ it ( "should return empty array for empty CommitDict" , ( ) => {
62+ const commitDict : CommitDict = new Map ( ) ;
63+
64+ const leafNodes = getLeafNodes ( commitDict ) ;
65+
66+ expect ( leafNodes ) . toEqual ( [ ] ) ;
67+ } ) ;
68+
69+ it ( "should not return nodes without branches as leaf nodes" , ( ) => {
70+ const commits : CommitRaw [ ] = [
71+ createMockCommitRaw ( "commit1" , [ ] ) ,
72+ createMockCommitRaw ( "commit2" , [ ] ) ,
73+ ] ;
74+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
75+
76+ const leafNodes = getLeafNodes ( commitDict ) ;
77+
78+ expect ( leafNodes ) . toEqual ( [ ] ) ;
79+ } ) ;
80+
81+ it ( "should return only nodes with branches when mixed" , ( ) => {
82+ const commits : CommitRaw [ ] = [
83+ createMockCommitRaw ( "commit1" , [ "main" ] ) ,
84+ createMockCommitRaw ( "commit2" , [ ] ) ,
85+ createMockCommitRaw ( "commit3" , [ "develop" ] ) ,
86+ createMockCommitRaw ( "commit4" , [ ] ) ,
87+ ] ;
88+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
89+
90+ const leafNodes = getLeafNodes ( commitDict ) ;
91+
92+ expect ( leafNodes ) . toHaveLength ( 2 ) ;
93+ expect ( leafNodes . map ( node => node . commit . id ) ) . toEqual (
94+ expect . arrayContaining ( [ "commit1" , "commit3" ] )
95+ ) ;
96+ } ) ;
97+ } ) ;
98+
99+ describe ( "type validation" , ( ) => {
100+ it ( "should return array elements with CommitNode type" , ( ) => {
101+ const commits : CommitRaw [ ] = [
102+ createMockCommitRaw ( "commit1" , [ "main" ] ) ,
103+ ] ;
104+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
105+
106+ const leafNodes = getLeafNodes ( commitDict ) ;
107+
108+ expect ( leafNodes [ 0 ] ) . toHaveProperty ( "commit" ) ;
109+ expect ( leafNodes [ 0 ] . commit ) . toHaveProperty ( "id" ) ;
110+ expect ( leafNodes [ 0 ] . commit ) . toHaveProperty ( "branches" ) ;
111+ expect ( Array . isArray ( leafNodes [ 0 ] . commit . branches ) ) . toBe ( true ) ;
112+ } ) ;
113+ } ) ;
114+
115+ describe ( "real-world scenarios" , ( ) => {
116+ it ( "should correctly find leaf nodes in git-like history" , ( ) => {
117+ const commits : CommitRaw [ ] = [
118+ createMockCommitRaw ( "abc123" , [ "main" ] , {
119+ message : "feat: add new feature" ,
120+ author : { name : "Developer 1" , email : "dev1@example.com" } ,
121+ } ) ,
122+ createMockCommitRaw ( "def456" , [ ] , {
123+ message : "fix: bug fix" ,
124+ author : { name : "Developer 2" , email : "dev2@example.com" } ,
125+ } ) ,
126+ createMockCommitRaw ( "ghi789" , [ "develop" , "feature/branch" ] , {
127+ message : "refactor: code cleanup" ,
128+ author : { name : "Developer 3" , email : "dev3@example.com" } ,
129+ } ) ,
130+ ] ;
131+ const commitDict : CommitDict = buildCommitDict ( commits ) ;
132+
133+ const leafNodes = getLeafNodes ( commitDict ) ;
134+
135+ expect ( leafNodes ) . toHaveLength ( 2 ) ;
136+ expect ( leafNodes . map ( node => node . commit . id ) ) . toEqual (
137+ expect . arrayContaining ( [ "abc123" , "ghi789" ] )
138+ ) ;
139+
140+ const mainBranchNode = leafNodes . find ( node => node . commit . id === "abc123" ) ;
141+ expect ( mainBranchNode ?. commit . message ) . toBe ( "feat: add new feature" ) ;
142+ expect ( mainBranchNode ?. commit . branches ) . toEqual ( [ "main" ] ) ;
143+ } ) ;
144+ } ) ;
145+ } ) ;
146+
147+ describe ( "isLeafNode" , ( ) => {
148+ const createMockCommitRaw = (
149+ id : string ,
150+ branches : string [ ] = [ ] ,
151+ overrides : Partial < CommitRaw > = { }
152+ ) : CommitRaw => ( {
153+ sequence : 1 ,
154+ id,
155+ parents : [ ] ,
156+ branches,
157+ tags : [ ] ,
158+ author : { name : "Test Author" , email : "test@example.com" } ,
159+ authorDate : new Date ( "2023-01-01" ) ,
160+ committer : { name : "Test Committer" , email : "test@example.com" } ,
161+ committerDate : new Date ( "2023-01-01" ) ,
162+ message : "Test commit message" ,
163+ differenceStatistic : {
164+ totalInsertionCount : 0 ,
165+ totalDeletionCount : 0 ,
166+ fileDictionary : { } ,
167+ } ,
168+ commitMessageType : "" ,
169+ ...overrides ,
170+ } ) ;
171+
172+ it ( "should return true for nodes with branches" , ( ) => {
173+ const node = { commit : createMockCommitRaw ( "test1" , [ "main" ] ) } ;
174+
175+ expect ( isLeafNode ( node ) ) . toBe ( true ) ;
176+ } ) ;
177+
178+ it ( "should return true for nodes with multiple branches" , ( ) => {
179+ const node = { commit : createMockCommitRaw ( "test1" , [ "main" , "develop" ] ) } ;
180+
181+ expect ( isLeafNode ( node ) ) . toBe ( true ) ;
182+ } ) ;
183+
184+ it ( "should return false for nodes without branches" , ( ) => {
185+ const node = { commit : createMockCommitRaw ( "test1" , [ ] ) } ;
186+
187+ expect ( isLeafNode ( node ) ) . toBe ( false ) ;
188+ } ) ;
189+
190+ it ( "should be determined by branches regardless of stemId" , ( ) => {
191+ const nodeWithoutBranches = {
192+ stemId : "stem1" ,
193+ commit : createMockCommitRaw ( "test1" , [ ] )
194+ } ;
195+
196+ const nodeWithBranches = {
197+ stemId : "stem1" ,
198+ commit : createMockCommitRaw ( "test2" , [ "main" ] )
199+ } ;
200+
201+ expect ( isLeafNode ( nodeWithoutBranches ) ) . toBe ( false ) ;
202+ expect ( isLeafNode ( nodeWithBranches ) ) . toBe ( true ) ;
203+ } ) ;
204+ } ) ;
0 commit comments