1
+ using System . Reflection ;
2
+ using CodeParser . Parser ;
3
+ using CodeParser . Parser . Config ;
4
+ using LibGit2Sharp ;
5
+
6
+ namespace ApprovalTestTool ;
7
+
8
+ internal class TestTool
9
+ {
10
+ /// <summary>
11
+ /// Automatic approval tool
12
+ /// For each line in the repositories.txt
13
+ /// 1. Clone or pull the repository
14
+ /// 2. Checkout the specified commit
15
+ /// 3. Run test code: Parse the solution and write the output to a file.
16
+ /// 4. Compare output with reference or copy to reference folder if not exists yet.
17
+ /// 5. Print test result
18
+ ///
19
+ /// Note: The reference files are not committed, so save space.
20
+ /// You can always check out an older tag and create the reference files.
21
+ /// </summary>
22
+ private static async Task Main ( string [ ] args )
23
+ {
24
+ var referenceFolder = @"d:\\ApprovalTests\\References" ;
25
+ var gitCloneFolder = @"d:\\ApprovalTests\\Repositories" ;
26
+
27
+ if ( args . Length == 2 )
28
+ {
29
+ referenceFolder = args [ 0 ] ;
30
+ gitCloneFolder = args [ 1 ] ;
31
+ }
32
+ else
33
+ {
34
+ Console . WriteLine ( "Usage: TestTool <reference-folder> <git-clone-folder>" ) ;
35
+ Console . WriteLine ( "Using default folders." ) ;
36
+ }
37
+
38
+
39
+ Console . WriteLine ( "Use reference folder: " + referenceFolder ) ;
40
+ Console . WriteLine ( "Use git clone folder: " + gitCloneFolder ) ;
41
+
42
+
43
+ EnsureDirectoryExists ( referenceFolder ) ;
44
+ EnsureDirectoryExists ( gitCloneFolder ) ;
45
+
46
+ var executablePath = Assembly . GetExecutingAssembly ( ) . Location ;
47
+ var executableDirectory = Path . GetDirectoryName ( executablePath ) ;
48
+ var repoFile = Path . Combine ( executableDirectory , "repositories.txt" ) ;
49
+
50
+ if ( ! File . Exists ( repoFile ) )
51
+ {
52
+ Console . WriteLine ( $ "Input file 'repositories.txt' not found in { executableDirectory } ") ;
53
+ return ;
54
+ }
55
+
56
+
57
+ Initializer . InitializeMsBuildLocator ( ) ;
58
+
59
+ foreach ( var line in File . ReadLines ( repoFile ) )
60
+ {
61
+ var parts = line . Split ( ',' ) ;
62
+ if ( parts . Length != 3 )
63
+ {
64
+ Console . WriteLine ( $ "Invalid input line: { line } ") ;
65
+ continue ;
66
+ }
67
+
68
+ var repoUrl = parts [ 0 ] ;
69
+ var slnRelativePath = parts [ 1 ] ;
70
+ var commitHash = parts [ 2 ] ;
71
+
72
+ await ProcessRepository ( repoUrl , slnRelativePath , commitHash , gitCloneFolder , referenceFolder ) ;
73
+ }
74
+ }
75
+
76
+ private static async Task ProcessRepository ( string repoUrl , string slnRelativePath , string commitHash ,
77
+ string gitCloneFolder , string referenceFolder )
78
+ {
79
+ var repoName = Path . GetFileNameWithoutExtension ( repoUrl ) ;
80
+ var repoPath = Path . Combine ( gitCloneFolder , repoName ) ;
81
+
82
+ // Clone or pull the repository
83
+ if ( ! Directory . Exists ( repoPath ) )
84
+ {
85
+ Repository . Clone ( repoUrl , repoPath ) ;
86
+ }
87
+ else
88
+ {
89
+ using ( var repo = new Repository ( repoPath ) )
90
+ {
91
+ Commands . Fetch ( repo , "origin" , Array . Empty < string > ( ) , new FetchOptions ( ) , null ) ;
92
+ }
93
+ }
94
+
95
+ // Checkout the specified commit
96
+ using ( var repo = new Repository ( repoPath ) )
97
+ {
98
+ var commit = repo . Lookup < Commit > ( commitHash ) ;
99
+ if ( commit == null )
100
+ {
101
+ Console . WriteLine ( $ "Commit { commitHash } not found in repository { repoName } ") ;
102
+ return ;
103
+ }
104
+
105
+ Commands . Checkout ( repo , commit ) ;
106
+ }
107
+
108
+ // Generate paths
109
+ var slnPath = Path . Combine ( repoPath , slnRelativePath ) ;
110
+ var outputFileName = $ "{ commitHash } .txt";
111
+ var outputPath = Path . Combine ( gitCloneFolder , outputFileName ) ;
112
+
113
+ // Run test code (placeholder)
114
+ await RunTestCode ( slnPath , outputPath ) ;
115
+
116
+ // Compare output with reference or copy to reference folder
117
+ var referencePath = Path . Combine ( referenceFolder , outputFileName ) ;
118
+ if ( File . Exists ( referencePath ) )
119
+ {
120
+ var areEqual = CompareFiles ( outputPath , referencePath ) ;
121
+ PrintColoredTestResult ( repoName , commitHash , areEqual ) ;
122
+ }
123
+ else
124
+ {
125
+ File . Copy ( outputPath , referencePath ) ;
126
+ Console . WriteLine ( $ "No reference file for { repoName } at { commitHash } . Created new reference file.") ;
127
+ }
128
+ }
129
+
130
+ private static async Task RunTestCode ( string slnPath , string outputPath )
131
+ {
132
+ var parserConfig = new ParserConfig ( new ProjectExclusionRegExCollection ( ) , 1 ) ;
133
+ var parser = new Parser ( parserConfig ) ;
134
+ var graph = await parser . ParseSolution ( slnPath ) ;
135
+ await File . WriteAllTextAsync ( outputPath , graph . ToDebug ( ) ) ;
136
+ }
137
+
138
+ private static bool CompareFiles ( string file1 , string file2 )
139
+ {
140
+ using var stream1 = File . OpenRead ( file1 ) ;
141
+ using var stream2 = File . OpenRead ( file2 ) ;
142
+ if ( stream1 . Length != stream2 . Length )
143
+ {
144
+ return false ;
145
+ }
146
+
147
+ using var reader1 = new StreamReader ( stream1 ) ;
148
+ using var reader2 = new StreamReader ( stream2 ) ;
149
+ while ( reader1 . ReadLine ( ) is { } line1 )
150
+ {
151
+ var line2 = reader2 . ReadLine ( ) ;
152
+ if ( line2 == null || line1 != line2 )
153
+ {
154
+ return false ;
155
+ }
156
+ }
157
+
158
+ // Since the files have the same length that should never happen.
159
+ return reader2 . ReadLine ( ) == null ;
160
+ }
161
+
162
+ private static void PrintColoredTestResult ( string repoName , string commitHash , bool passed )
163
+ {
164
+ Console . Write ( $ "Test for { repoName } at { commitHash } : ") ;
165
+ Console . ForegroundColor = passed ? ConsoleColor . Green : ConsoleColor . Red ;
166
+ Console . WriteLine ( passed ? "Passed" : "Failed" ) ;
167
+ Console . ResetColor ( ) ;
168
+ }
169
+
170
+
171
+ private static void EnsureDirectoryExists ( string path )
172
+ {
173
+ if ( ! Directory . Exists ( path ) )
174
+ {
175
+ try
176
+ {
177
+ Directory . CreateDirectory ( path ) ;
178
+ Console . WriteLine ( $ "Created directory: { path } ") ;
179
+ }
180
+ catch ( Exception ex )
181
+ {
182
+ Console . WriteLine ( $ "Error creating directory { path } : { ex . Message } ") ;
183
+ Environment . Exit ( 1 ) ;
184
+ }
185
+ }
186
+ }
187
+ }
0 commit comments