1- // Copyright (c) 2024 SIL Global
1+ // Copyright (c) 2025 SIL Global
22// This software is licensed under the MIT License (http://opensource.org/licenses/MIT)
33
44using System ;
55using NUnit . Framework ;
6+ using SIL . Providers ;
7+ using SIL . TestUtilities . Providers ;
8+
69// Sadly, Resharper wants to change Is.EqualTo to NUnit.Framework.Is.EqualTo
710// ReSharper disable AccessToStaticMemberViaDerivedType
811
@@ -11,6 +14,19 @@ namespace SIL.BuildTasks.Tests
1114 [ TestFixture ]
1215 public class FileUpdateTests
1316 {
17+ [ SetUp ]
18+ public void Setup ( )
19+ {
20+ DateTimeProvider . SetProvider (
21+ new ReproducibleDateTimeProvider ( new DateTime ( 2026 , 4 , 16 ) ) ) ;
22+ }
23+
24+ [ TearDown ]
25+ public void TearDown ( )
26+ {
27+ DateTimeProvider . ResetToDefault ( ) ;
28+ }
29+
1430 [ TestCase ( "This is the story of the frog prince." , "frog" , "monkey" ,
1531 ExpectedResult = "This is the story of the monkey prince." ) ]
1632 [ TestCase ( "This is the story of the frog prince." , "f[^ ]+g" , "toad" ,
@@ -62,6 +78,106 @@ public void GetModifiedContents_RegexTextNotMatched_Throws(string origContents,
6278 Assert . That ( ex . Message , Is . EqualTo ( $ "No replacements made. Regex: '{ regex } '; ReplacementText: '{ replacement } '") ) ;
6379 }
6480
81+ [ TestCase ( "_DATE_ _VERSION_\r \n Stuff" , "_DATE_" , "M/yyyy" , "4/2026 3.2.1\r \n Stuff" ) ]
82+ [ TestCase ( "_DATE_ _VERSION_\r \n Stuff done before _DATE_" , "_DATE_" , "M/yyyy" , "4/2026 3.2.1\r \n Stuff done before 4/2026" ) ]
83+ [ TestCase ( "&DATE; _VERSION_\r \n - point #1" , "&DATE;" , "dd-MM-yy" , "16-04-26 3.2.1\r \n - point #1" ) ]
84+ [ TestCase ( "DATE _VERSION_" , "DATE" , "dd MMMM, yyyy" , "16 April, 2026 3.2.1" ) ]
85+ [ TestCase ( "DATE _VERSION_" , "DATE" , null , "16/Apr/2026 3.2.1" ) ] // Uses default date format
86+ public void GetModifiedContents_DateLiteral_InsertsDateWithSpecifiedDateFormat (
87+ string origContents , string datePlaceholder , string dateFormat ,
88+ string expectedResult )
89+ {
90+ var updater = new FileUpdate
91+ {
92+ Regex = "_VERSION_" ,
93+ ReplacementText = "3.2.1" ,
94+ DatePlaceholder = datePlaceholder ,
95+ DateFormat = dateFormat
96+ } ;
97+
98+ var result = updater . GetModifiedContents ( origContents ) ;
99+ Assert . That ( result , Is . EqualTo ( expectedResult ) ) ;
100+ }
101+
102+ [ TestCase ( "_DATE_ _VERSION_\r \n Stuff" , "M/yyyy" , "4/2026 3.2.1\r \n Stuff" ) ]
103+ [ TestCase ( "_DATE_ _VERSION_\r \n Stuff done before _DATE_" , "dd-MM-yy" , "16-04-26 3.2.1\r \n Stuff done before 16-04-26" ) ]
104+ public void GetModifiedContents_SpecialDatePlaceholderButFileDoesNotSpecifyFormat_InsertsDateWithSpecifiedDateFormat (
105+ string origContents , string dateFormat , string expectedResult )
106+ {
107+ var updater = new FileUpdate
108+ {
109+ Regex = "_VERSION_" ,
110+ ReplacementText = "3.2.1" ,
111+ DatePlaceholder = "_DATE(*)_" ,
112+ DateFormat = dateFormat
113+ } ;
114+
115+ var result = updater . GetModifiedContents ( origContents ) ;
116+ Assert . That ( result , Is . EqualTo ( expectedResult ) ) ;
117+ }
118+
119+ [ TestCase ( "MM-yy" ) ]
120+ [ TestCase ( "dd MMMM" ) ]
121+ public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingFormat_InsertsDateWithFormatFromFile (
122+ string format )
123+ {
124+ var origContents = $ "_DATE({ format } )_\r \n Stuff";
125+
126+ var updater = new FileUpdate
127+ {
128+ Regex = "(.*)" ,
129+ ReplacementText = "$1" ,
130+ DatePlaceholder = "_DATE(*)_" ,
131+ } ;
132+
133+ var currentDate = DateTimeProvider . Current . UtcNow . ToString ( format ) ;
134+
135+ var result = updater . GetModifiedContents ( origContents ) ;
136+ Assert . That ( result , Is . EqualTo ( $ "{ currentDate } \r \n Stuff") ) ;
137+ }
138+
139+ [ TestCase ( "MM-yyyy" , "d MMMM yy" ) ]
140+ [ TestCase ( "dd MMMM" , "MM/dd/yyyy" ) ]
141+ public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingMultipleFormats_InsertsDateWithFormatsFromFile (
142+ string format1 , string format2 )
143+ {
144+ var origContents = $ "First _DATE({ format1 } )_\r \n Second _DATE_\r \n Last _DATE({ format2 } )_";
145+
146+ var updater = new FileUpdate
147+ {
148+ Regex = "(.*)" ,
149+ ReplacementText = "$1" ,
150+ DatePlaceholder = "_DATE(*)_" ,
151+ } ;
152+
153+ var currentDate = DateTimeProvider . Current . UtcNow ;
154+ var currentDate1 = currentDate . ToString ( format1 ) ;
155+ var currentDate2 = currentDate . ToString ( format2 ) ;
156+
157+ var result = updater . GetModifiedContents ( origContents ) ;
158+ Assert . That ( result , Is . EqualTo ( $ "First { currentDate1 } \r \n Second 16/Apr/2026\r \n Last { currentDate2 } ") ) ;
159+ }
160+
161+ [ TestCase ( "es" , "abril" ) ]
162+ [ TestCase ( "fr" , "avril" ) ]
163+ public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyingFormat_InsertsLocaleSpecificDateWithFormatFromFile (
164+ string locale , string localizedMonthName )
165+ {
166+ var origContents = "_DATE(d MMMM yyyy)_\r \n Stuff" ;
167+
168+ var updater = new FileUpdate
169+ {
170+ File = $ "ReleaseNotes.{ locale } .md",
171+ FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$" ,
172+ Regex = "(.*)" ,
173+ ReplacementText = "$1" ,
174+ DatePlaceholder = "_DATE(*)_" ,
175+ } ;
176+
177+ var result = updater . GetModifiedContents ( origContents ) ;
178+ Assert . That ( result , Is . EqualTo ( $ "16 { localizedMonthName } 2026\r \n Stuff") ) ;
179+ }
180+
65181 [ Test ]
66182 public void GetModifiedContents_InvalidRegex_Throws ( )
67183 {
@@ -74,5 +190,89 @@ public void GetModifiedContents_InvalidRegex_Throws()
74190 var ex = Assert . Throws < Exception > ( ( ) => updater . GetModifiedContents ( "Whatever" ) ) ;
75191 Assert . That ( ex . Message , Is . EqualTo ( $ "Invalid regular expression: parsing \" { updater . Regex } \" - Not enough )'s.") ) ;
76192 }
193+
194+ [ Test ]
195+ public void FileLocalePattern_InvalidRegex_ThrowsArgumentException ( )
196+ {
197+ const string expr = @"ReleaseNotes\.(.*\.md" ;
198+ Assert . That ( ( ) =>
199+ {
200+ _ = new FileUpdate
201+ {
202+ FileLocalePattern = expr ,
203+ ReplacementText = "oops"
204+ } ;
205+ } , Throws . ArgumentException . With . Message . EqualTo ( $ "FileLocalePattern: Invalid regular expression: parsing \" { expr } \" - Not enough )'s.") ) ;
206+ }
207+
208+ [ TestCase ( "es" ) ]
209+ [ TestCase ( "fr" ) ]
210+ [ TestCase ( "zh-CN" ) ]
211+ public void GetCultureFromFileName_MatchLocaleGroupToKnownCulture_GetsSpecifiedCulture ( string localeSpecifier )
212+ {
213+ var fileUpdater = new FileUpdate
214+ {
215+ File = $ "ReleaseNotes.{ localeSpecifier } .md",
216+ FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$" ,
217+ } ;
218+
219+ Assert . That ( fileUpdater . GetCultureFromFileName ( ) . IetfLanguageTag ,
220+ Is . EqualTo ( localeSpecifier ) ) ;
221+ }
222+
223+ [ TestCase ( "zz-Unknown" ) ]
224+ [ TestCase ( "qq-Weird" ) ]
225+ public void GetCultureFromFileName_MatchLocaleGroupToUnknownCulture_ReturnsNull ( string localeSpecifier )
226+ {
227+ var fileUpdater = new FileUpdate
228+ {
229+ File = $ "ReleaseNotes.{ localeSpecifier } .md",
230+ FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$" ,
231+ } ;
232+
233+ Assert . That ( fileUpdater . GetCultureFromFileName ( ) , Is . Null ) ;
234+ }
235+
236+ [ TestCase ( "es" ) ]
237+ [ TestCase ( "fr-FR" ) ]
238+ [ TestCase ( "de" ) ]
239+ public void GetCultureFromFileName_EntireMatchIsKnownCulture_GetsSpecifiedCulture ( string localeSpecifier )
240+ {
241+ var fileUpdater = new FileUpdate
242+ {
243+ File = $ "ReleaseNotes.{ localeSpecifier } .md",
244+ FileLocalePattern = @"(?<=\.)es|fr-FR|de(?=\.)" ,
245+ } ;
246+
247+ Assert . That ( fileUpdater . GetCultureFromFileName ( ) . IetfLanguageTag ,
248+ Is . EqualTo ( localeSpecifier ) ) ;
249+ }
250+
251+ [ TestCase ( "My.bat.ate.your.homework.md" , @"(?<=\.)[a-z]{4}(?=\.)" ) ]
252+ [ TestCase ( "ReleaseNotes.htm" , ".+" ) ]
253+ public void GetCultureFromFileName_EntireMatchIsUnknownCulture_ReturnsNull ( string fileName , string pattern )
254+ {
255+ var fileUpdater = new FileUpdate
256+ {
257+ File = fileName ,
258+ FileLocalePattern = pattern ,
259+ } ;
260+
261+ Assert . That ( fileUpdater . GetCultureFromFileName ( ) , Is . Null ) ;
262+ }
263+
264+ [ TestCase ( "My.bat.ate.your.homework.md" , @"(?<=\.)[a-z]{22}(?=\.)" ) ]
265+ [ TestCase ( "ReleaseNotes.htm" , @"(?<=\.)es|fr-FR|de(?=\.)" ) ]
266+ [ TestCase ( "ReleaseNotes.htm" , @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$" ) ]
267+ public void GetCultureFromFileName_NoMatch_ReturnsNull ( string fileName , string pattern )
268+ {
269+ var fileUpdater = new FileUpdate
270+ {
271+ File = fileName ,
272+ FileLocalePattern = pattern ,
273+ } ;
274+
275+ Assert . That ( fileUpdater . GetCultureFromFileName ( ) , Is . Null ) ;
276+ }
77277 }
78278}
0 commit comments