private bool TryParse <T>(string filename, DateVariant <T> dateVariant, out T value, out ParsedFilename result) { var match = dateVariant.Regex.Match(filename); if (match.Success) { var timePart = match.Groups[nameof(Time)].Value + match.Groups[nameof(Offset)].Value; var parseString = match.Groups[nameof(Date)] + (timePart == string.Empty ? timePart : InvariantDateTimeSeparator + timePart); var parseResult = dateVariant.ParseFormat.Parse(parseString); if (parseResult.Success) { var location = this.ParseLocation(match.Groups[nameof(Suffix)].Value); result = new ParsedFilename() { Extension = match.Groups[nameof(Extension)].Value, Location = location, Prefix = match.Groups[nameof(Prefix)].Value, DatePart = ReconstructDatePart(), Suffix = match.Groups[nameof(Suffix)].Value, }; value = parseResult.Value; return(true); } } value = default; result = null; return(false); string ReconstructDatePart() { return(new[] { nameof(Date), nameof(Separator), nameof(Time), nameof(Offset) } .Select(s => match.Groups[s]) .OrderBy(g => g.Index) .Aggregate(string.Empty, (seed, group) => seed + group.Value)); } }
public void CanParse(FilenameParsingFixtureModel test) { $"Given {test}".x(Nop); ParsedFilename actual = null; "When I parse the filename".x(() => actual = this.parser.Parse(test.Filename)); if (test.ExpectedDateTime.HasValue) { $"Then local date should have the value {test.ExpectedDateTime}" .x(() => actual.LocalDateTime.ShouldBe(test.ExpectedDateTime, $"{test.ExpectedDateTime:o} ≠ {actual.LocalDateTime:o}")); if (test.ExpectedTzOffset.HasValue) { OffsetDateTime?date = null; "Given the constructed date offset" .x(() => date = test.ExpectedDateTime?.WithOffset(test.ExpectedTzOffset.Value)); $"Then the offset date should have the expected value {test.ExpectedDateTime}{test.ExpectedTzOffset}" .x(() => actual.OffsetDateTime.ShouldBe(date, $"{date:o} ≠ {actual.OffsetDateTime:o}")); } else { "But the offset date should NOT have a value" .x(() => Assert.Null(actual.OffsetDateTime)); } } else { "Then local date should NOT have a value" .x(() => Assert.Null(actual.LocalDateTime)); } if (test.ExpectedLongitude.HasValue) { $"And then the latitude parsed in this filename should be {test.ExpectedLatitude}" .x(() => Assert.Equal(test.ExpectedLatitude.Value, (double)actual.Location.Latitude, Wgs84Epsilon)); $"and the longitude should be {test.ExpectedLongitude}" .x(() => Assert.Equal(test.ExpectedLongitude.Value, (double)actual.Location.Longitude, Wgs84Epsilon)); "and the location sample date should be set" .x(() => Assert.Equal(actual.OffsetDateTime?.ToInstant(), actual.Location.SampleDateTime)); } else { "And in this case we do not find a location" .x(() => Assert.Null(actual.Location)); } "And the prefix should be set" .x(() => Assert.Equal(test.Prefix, actual.Prefix)); "Along with the suffix" .x(() => Assert.Equal(test.Suffix, actual.Suffix)); "And the extension field should be set" .x(() => Assert.Equal(test.Extension, actual.Extension)); string datePart = string.Empty; "Now given what we expect the date part to be" .x(() => datePart = !test.ExpectedDateTime.HasValue ? string.Empty : test.Filename .AsSpan(test.Prefix.Length) .Slice( 0, test.Filename.Length - test.Prefix.Length - test.Suffix.Length - test.Extension.Length) .ToString()); "then the DatePart should have the remainder of the string" .x(() => Assert.Equal(datePart, actual.DatePart)); }