Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added
- [SIL.BuildTasks] Added FileUpdate.FileLocalePattern (optional param) to infer a locale (e.g., for a localized release notes file) to use when doing date insertion involving month names or abbreviations.

### Changed

- [SIL.BuildTasks] Changed FileUpdate.DatePlaceholder to allow the caller to specify a special placeholder `_DATE(*)_` that will look not only for `_DATE_` but also variants that include a date format specifier, such as `_DATE(MMM d, yyyy)_` or `_DATE(MM/yyyy)_` and will use the date format specified instead of the DateFormat.

## [3.1.1] - 2025-03-18
### Changed

Expand Down
199 changes: 199 additions & 0 deletions SIL.BuildTasks.Tests/FileUpdateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// This software is licensed under the MIT License (http://opensource.org/licenses/MIT)

using System;
using System.Globalization;
using NUnit.Framework;
// Sadly, Resharper wants to change Is.EqualTo to NUnit.Framework.Is.EqualTo
// ReSharper disable AccessToStaticMemberViaDerivedType
Expand Down Expand Up @@ -62,6 +63,120 @@ public void GetModifiedContents_RegexTextNotMatched_Throws(string origContents,
Assert.That(ex.Message, Is.EqualTo($"No replacements made. Regex: '{regex}'; ReplacementText: '{replacement}'"));
}

[TestCase("_DATE_ _VERSION_\r\nStuff", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff")]
[TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "_DATE_", "M/yyyy", "{0} 3.2.1\r\nStuff done before {0}")]
[TestCase("&DATE; _VERSION_\r\n- point #1", "&DATE;", "dd-MM-yy", "{0} 3.2.1\r\n- point #1")]
[TestCase("DATE _VERSION_", "DATE", "dd MMMM, yyyy", "{0} 3.2.1")]
[TestCase("DATE _VERSION_", "DATE", null, "{0} 3.2.1")]
public void GetModifiedContents_DateLiteral_InsertsDateWithSpecifiedDateFormat(
string origContents, string datePlaceholder, string dateFormat,
string expectedResultFormat)
{
var updater = new FileUpdate
{
Regex = "_VERSION_",
ReplacementText = "3.2.1",
DatePlaceholder = datePlaceholder,
DateFormat = dateFormat
};

var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat);

var result = updater.GetModifiedContents(origContents);
var expectedResult = string.Format(expectedResultFormat, currentDate);
Assert.That(result, Is.EqualTo(expectedResult));
}

[TestCase("_DATE_ _VERSION_\r\nStuff", "M/yyyy", "{0} 3.2.1\r\nStuff")]
[TestCase("_DATE_ _VERSION_\r\nStuff done before _DATE_", "dd-MM-yy", "{0} 3.2.1\r\nStuff done before {0}")]
public void GetModifiedContents_SpecialDatePlaceholderButFileDoesNotSpecifyFormat_InsertsDateWithSpecifiedDateFormat(
string origContents, string dateFormat, string expectedResultFormat)
{
var updater = new FileUpdate
{
Regex = "_VERSION_",
ReplacementText = "3.2.1",
DatePlaceholder = "_DATE(*)_",
DateFormat = dateFormat
};

var currentDate = DateTime.UtcNow.Date.ToString(dateFormat ?? updater.DateFormat);

var result = updater.GetModifiedContents(origContents);
var expectedResult = string.Format(expectedResultFormat, currentDate);
Assert.That(result, Is.EqualTo(expectedResult));
}

[TestCase("MM-yy")]
[TestCase("dd MMMM")]
public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingFormat_InsertsDateWithFormatFromFile(
string format)
{
var origContents = $"_DATE({format})_\r\nStuff";

var updater = new FileUpdate
{
Regex = "(.*)",
ReplacementText = "$1",
DatePlaceholder = "_DATE(*)_",
};

var currentDate = DateTime.UtcNow.Date.ToString(format);

var result = updater.GetModifiedContents(origContents);
Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff"));
}

[TestCase("MM-yyyy", "d MMMM yy")]
[TestCase("dd MMMM", "MM/dd/yyyy")]
public void GetModifiedContents_SpecialDatePlaceholderWithFileSpecifyingMultipleFormats_InsertsDateWithFormatsFromFile(
string format1, string format2)
{
var origContents = $"First _DATE({format1})_\r\nSecond _DATE_\r\nLast _DATE({format2})_";

var updater = new FileUpdate
{
Regex = "(.*)",
ReplacementText = "$1",
DatePlaceholder = "_DATE(*)_",
};

var currentDate1 = DateTime.UtcNow.Date.ToString(format1);
var currentDateInDefaultFmt = DateTime.UtcNow.Date.ToString(updater.DateFormat);
var currentDate2 = DateTime.UtcNow.Date.ToString(format2);

var result = updater.GetModifiedContents(origContents);
Assert.That(result, Is.EqualTo($"First {currentDate1}\r\nSecond {currentDateInDefaultFmt}\r\nLast {currentDate2}"));
}

[TestCase("es")]
[TestCase("fr")]
public void GetModifiedContents_SpecialDatePlaceholderWithLocalizedFileSpecifyingFormat_InsertsLocaleSpecificDateWithFormatFromFile(string locale)
{
var origContents = "_DATE(d MMMM yyyy)_\r\nStuff";

var updater = new FileUpdate
{
File = $"ReleaseNotes.{locale}.md",
FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$",
Regex = "(.*)",
ReplacementText = "$1",
DatePlaceholder = "_DATE(*)_",
};

var currentDate = string.Format(DateTime.UtcNow.Date.ToString("d {0} yyyy"),
GetMonthName(locale, DateTime.UtcNow.Month));

var result = updater.GetModifiedContents(origContents);
Assert.That(result, Is.EqualTo($"{currentDate}\r\nStuff"));
}

private string GetMonthName(string locale, int month)
{
var culture = new CultureInfo(locale);
return culture.DateTimeFormat.GetMonthName(month);
}

[Test]
public void GetModifiedContents_InvalidRegex_Throws()
{
Expand All @@ -74,5 +189,89 @@ public void GetModifiedContents_InvalidRegex_Throws()
var ex = Assert.Throws<Exception>(() => updater.GetModifiedContents("Whatever"));
Assert.That(ex.Message, Is.EqualTo($"Invalid regular expression: parsing \"{updater.Regex}\" - Not enough )'s."));
}

[Test]
public void FileLocalePattern_InvalidRegex_ThrowsArgumentException()
{
const string expr = @"ReleaseNotes\.(.*\.md";
Assert.That(() =>
{
_ = new FileUpdate
{
FileLocalePattern = expr,
ReplacementText = "oops"
};
}, Throws.ArgumentException.With.Message.EqualTo($"FileLocalePattern: Invalid regular expression: parsing \"{expr}\" - Not enough )'s."));
}

[TestCase("es")]
[TestCase("fr")]
[TestCase("zh-CN")]
public void GetCultureFromFileName_MatchLocaleGroupToKnownCulture_GetsSpecifiedCulture(string localeSpecifier)
{
var fileUpdater = new FileUpdate
{
File = $"ReleaseNotes.{localeSpecifier}.md",
FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$",
};

Assert.That(fileUpdater.GetCultureFromFileName().IetfLanguageTag,
Is.EqualTo(localeSpecifier));
}

[TestCase("zz-Unknown")]
[TestCase("qq-Weird")]
public void GetCultureFromFileName_MatchLocaleGroupToUnknownCulture_ReturnsNull(string localeSpecifier)
{
var fileUpdater = new FileUpdate
{
File = $"ReleaseNotes.{localeSpecifier}.md",
FileLocalePattern = @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$",
};

Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null);
}

[TestCase("es")]
[TestCase("fr-FR")]
[TestCase("de")]
public void GetCultureFromFileName_EntireMatchIsKnownCulture_GetsSpecifiedCulture(string localeSpecifier)
{
var fileUpdater = new FileUpdate
{
File = $"ReleaseNotes.{localeSpecifier}.md",
FileLocalePattern = @"(?<=\.)es|fr-FR|de(?=\.)",
};

Assert.That(fileUpdater.GetCultureFromFileName().IetfLanguageTag,
Is.EqualTo(localeSpecifier));
}

[TestCase("My.bat.ate.your.homework.md", @"(?<=\.)[a-z]{4}(?=\.)")]
[TestCase("ReleaseNotes.htm", ".+")]
public void GetCultureFromFileName_EntireMatchIsUnknownCulture_ReturnsNull(string fileName, string pattern)
{
var fileUpdater = new FileUpdate
{
File = fileName,
FileLocalePattern = pattern,
};

Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null);
}

[TestCase("My.bat.ate.your.homework.md", @"(?<=\.)[a-z]{22}(?=\.)")]
[TestCase("ReleaseNotes.htm", @"(?<=\.)es|fr-FR|de(?=\.)")]
[TestCase("ReleaseNotes.htm", @"\.(?<locale>[a-z]{2}(-\w+)?)\.md$")]
public void GetCultureFromFileName_NoMatch_ReturnsNull(string fileName, string pattern)
{
var fileUpdater = new FileUpdate
{
File = fileName,
FileLocalePattern = pattern,
};

Assert.That(fileUpdater.GetCultureFromFileName(), Is.Null);
}
}
}
Loading
Loading