diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6504da6..a44dfbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,3 +42,5 @@ jobs: run: dotnet build --no-restore - name: Test run: dotnet test --no-build --verbosity normal + env: + RUNON_GITHUB: y diff --git a/Directory.Build.props b/Directory.Build.props index faa0ff0..7e68cc9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,4 +9,8 @@ $(ArtifactsDir)bin\$(MSBuildProjectName)\ $(ArtifactsDir)nuget\$(Configuration)\ + + + 1.16.2 + \ No newline at end of file diff --git a/MdXaml.Html/MdXaml.Html.csproj b/MdXaml.Html/MdXaml.Html.csproj index 8fe17ef..80c0dc6 100644 --- a/MdXaml.Html/MdXaml.Html.csproj +++ b/MdXaml.Html/MdXaml.Html.csproj @@ -2,7 +2,7 @@ netcoreapp3.0;net45;net5.0-windows MdXaml.Html - 1.16.1 + $(PackageVersion) whistyun Markdown XAML processor diff --git a/MdXaml.Plugins/MdXaml.Plugins.csproj b/MdXaml.Plugins/MdXaml.Plugins.csproj index 45b8818..7f71b07 100644 --- a/MdXaml.Plugins/MdXaml.Plugins.csproj +++ b/MdXaml.Plugins/MdXaml.Plugins.csproj @@ -3,7 +3,7 @@ netcoreapp3.0;net45;net5.0-windows MdXaml.Plugins - 1.16.1 + $(PackageVersion) whistyun Markdown XAML processor diff --git a/MdXaml.Svg/MdXaml.Svg.csproj b/MdXaml.Svg/MdXaml.Svg.csproj index 7338017..a837930 100644 --- a/MdXaml.Svg/MdXaml.Svg.csproj +++ b/MdXaml.Svg/MdXaml.Svg.csproj @@ -3,7 +3,7 @@ netcoreapp3.0;net45;net5.0-windows MdXaml.Svg - 1.16.1 + $(PackageVersion) whistyun Markdown XAML processor diff --git a/MdXaml.sln b/MdXaml.sln index d4cfc30..8f815a5 100644 --- a/MdXaml.sln +++ b/MdXaml.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29519.181 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32922.545 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MdXaml", "MdXaml\MdXaml.csproj", "{3B285B6B-C6C9-4FF5-AD2B-04808862D81E}" EndProject @@ -40,6 +40,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MdXaml.Html.Test", "tests\M EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MdXaml.Plugins", "MdXaml.Plugins\MdXaml.Plugins.csproj", "{823DB5D5-17C0-4418-895C-A28DD7D04CE9}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualTest", "tests\VisualTest\VisualTest.csproj", "{F07D55AE-63CB-4098-9C85-8A6255A7ED54}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualTestApp", "tests\VisualTestApp\VisualTestApp.csproj", "{9BF2BC76-8D51-4595-B9EE-6DAF296BEC58}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -102,6 +106,14 @@ Global {823DB5D5-17C0-4418-895C-A28DD7D04CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU {823DB5D5-17C0-4418-895C-A28DD7D04CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU {823DB5D5-17C0-4418-895C-A28DD7D04CE9}.Release|Any CPU.Build.0 = Release|Any CPU + {F07D55AE-63CB-4098-9C85-8A6255A7ED54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F07D55AE-63CB-4098-9C85-8A6255A7ED54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F07D55AE-63CB-4098-9C85-8A6255A7ED54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F07D55AE-63CB-4098-9C85-8A6255A7ED54}.Release|Any CPU.Build.0 = Release|Any CPU + {9BF2BC76-8D51-4595-B9EE-6DAF296BEC58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BF2BC76-8D51-4595-B9EE-6DAF296BEC58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BF2BC76-8D51-4595-B9EE-6DAF296BEC58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BF2BC76-8D51-4595-B9EE-6DAF296BEC58}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -116,6 +128,8 @@ Global {C539C7B4-BBF2-4AC2-A732-0C47E125CCD2} = {435867FA-EE25-4708-9BBA-8509ABC7E389} {C45A1400-B4E9-4638-BF1F-4BB38CEC5E93} = {09BEAB2A-F47E-4D2B-AE81-8DC1BBB52638} {CEF2B49F-90AF-4B65-AA0C-A12AB1C0A18F} = {09BEAB2A-F47E-4D2B-AE81-8DC1BBB52638} + {F07D55AE-63CB-4098-9C85-8A6255A7ED54} = {09BEAB2A-F47E-4D2B-AE81-8DC1BBB52638} + {9BF2BC76-8D51-4595-B9EE-6DAF296BEC58} = {09BEAB2A-F47E-4D2B-AE81-8DC1BBB52638} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23DF7019-3B25-4B82-8955-25F1DDD72D84} diff --git a/MdXaml/ImageLoaderManager.cs b/MdXaml/ImageLoaderManager.cs index 57bb92e..1737cc9 100644 --- a/MdXaml/ImageLoaderManager.cs +++ b/MdXaml/ImageLoaderManager.cs @@ -134,9 +134,13 @@ public async Task> LoadImageAsync(IEnumerable resourceU { var imgSource = new BitmapImage(); imgSource.BeginInit(); + // close the stream after the BitmapImage is created + imgSource.CacheOption = BitmapCacheOption.OnLoad; imgSource.StreamSource = stream; imgSource.EndInit(); + stream.Close(); + return imgSource; } catch { } @@ -156,6 +160,7 @@ public async Task> LoadImageAsync(IEnumerable resourceU catch { } } + stream.Close(); return null; } @@ -202,25 +207,25 @@ private static async Task> OpenStreamAsync(Uri resourceUrl) } return new Result("unsupport scheme"); - } - private static async Task CheckSupportSeek(Stream stream) - { - if (stream.CanSeek) - return stream; - return await AsMemoryStream(stream); - } + static async Task CheckSupportSeek(Stream stream) + { + if (stream.CanSeek) + return stream; - private static async Task AsMemoryStream(Stream stream) - { - var ms = new MemoryStream(); - await stream.CopyToAsync(ms); - stream.Close(); + return await AsMemoryStream(stream); + } - return ms; - } + static async Task AsMemoryStream(Stream stream) + { + var ms = new MemoryStream(); + await stream.CopyToAsync(ms); + stream.Close(); + return ms; + } + } public class Result where T : class { diff --git a/MdXaml/MarkdownScrollViewer.cs b/MdXaml/MarkdownScrollViewer.cs index c528bf1..b229597 100644 --- a/MdXaml/MarkdownScrollViewer.cs +++ b/MdXaml/MarkdownScrollViewer.cs @@ -349,7 +349,7 @@ bool TryOpen(Uri path) throw new ArgumentException($"unsupport schema {path.Scheme}"); } - var assetPathRoot = path.Scheme == "file" ? path.LocalPath : path.AbsoluteUri; + var assetPathRoot = path.Scheme == "file" ? Path.GetDirectoryName(path.LocalPath) : path.AbsoluteUri; Engine.AssetPathRoot = assetPathRoot; @@ -384,7 +384,7 @@ bool TryOpen(Uri path) } else { - var assetPath = Path.Combine(AssetPathRoot, source.LocalPath); + var assetPath = Path.Combine(AssetPathRoot, source.ToString()); TryOpen(new Uri(assetPath)); } } diff --git a/MdXaml/MdXaml.csproj b/MdXaml/MdXaml.csproj index faeb9b7..478f237 100644 --- a/MdXaml/MdXaml.csproj +++ b/MdXaml/MdXaml.csproj @@ -4,7 +4,7 @@ netcoreapp3.0;net45;net5.0-windows true MdXaml - 1.16.1 + $(PackageVersion) Bevan Arps(original); whistyun Markdown XAML processor diff --git a/MdXaml/MdXamlMigfree.csproj b/MdXaml/MdXamlMigfree.csproj index 07587f3..878cbed 100644 --- a/MdXaml/MdXamlMigfree.csproj +++ b/MdXaml/MdXamlMigfree.csproj @@ -4,7 +4,7 @@ netcoreapp3.0;net45;net5.0-windows true MdXaml_migfree - 1.16.1 + $(PackageVersion) Bevan Arps(original); whistyun Markdown XAML processor diff --git a/tests/MdXaml.Test/Out/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/Out/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index bdfd19c..3a2f03c 100644 --- a/tests/MdXaml.Test/Out/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/Out/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/MdXaml.Test/Out/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/Out/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index bdfd19c..3a2f03c 100644 --- a/tests/MdXaml.Test/Out/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/Out/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/MdXaml.Test/Out/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/Out/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index 54e2427..a7f3f90 100644 --- a/tests/MdXaml.Test/Out/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/Out/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/MdXaml.Test/OutMF/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/OutMF/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index bdfd19c..3a2f03c 100644 --- a/tests/MdXaml.Test/OutMF/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/OutMF/core/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/MdXaml.Test/OutMF/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/OutMF/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index bdfd19c..3a2f03c 100644 --- a/tests/MdXaml.Test/OutMF/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/OutMF/dotnet/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/MdXaml.Test/OutMF/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt b/tests/MdXaml.Test/OutMF/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt index 54e2427..a7f3f90 100644 --- a/tests/MdXaml.Test/OutMF/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt +++ b/tests/MdXaml.Test/OutMF/framework/Tests.Transform_givenImages2_generatesExpectedResult.approved.txt @@ -1,13 +1,13 @@ - A remote . - Images side by side + A remote . + Images side by side - + - A resource image . A local image . + A resource image . A local image . diff --git a/tests/VisualTest/Assets/Markdown.txt b/tests/VisualTest/Assets/Markdown.txt new file mode 100644 index 0000000..4438271 --- /dev/null +++ b/tests/VisualTest/Assets/Markdown.txt @@ -0,0 +1,7 @@ +# Markdown Resource + +![image1.bmp](image1.bmp) +![image2.png](image2.png) +![image3.jpg](image3.jpg) +![image4.svg](image4.svg) +![image5.txt](image5.txt) \ No newline at end of file diff --git a/tests/VisualTest/Assets/image1.bmp b/tests/VisualTest/Assets/image1.bmp new file mode 100644 index 0000000..36d8d40 Binary files /dev/null and b/tests/VisualTest/Assets/image1.bmp differ diff --git a/tests/VisualTest/Assets/image2.png b/tests/VisualTest/Assets/image2.png new file mode 100644 index 0000000..44aef93 Binary files /dev/null and b/tests/VisualTest/Assets/image2.png differ diff --git a/tests/VisualTest/Assets/image3.jpg b/tests/VisualTest/Assets/image3.jpg new file mode 100644 index 0000000..8ad75bb Binary files /dev/null and b/tests/VisualTest/Assets/image3.jpg differ diff --git a/tests/VisualTest/Assets/image4.svg b/tests/VisualTest/Assets/image4.svg new file mode 100644 index 0000000..a93ccaa --- /dev/null +++ b/tests/VisualTest/Assets/image4.svg @@ -0,0 +1,61 @@ + + +Created by potrace 1.12, written by Peter Selinger 2001-2015 + + + + + + \ No newline at end of file diff --git a/tests/VisualTest/Assets/image5.txt b/tests/VisualTest/Assets/image5.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/VisualTest/Class1.cs b/tests/VisualTest/Class1.cs new file mode 100644 index 0000000..59dd721 --- /dev/null +++ b/tests/VisualTest/Class1.cs @@ -0,0 +1,127 @@ +#if !OnGitHubAction +using NUnit.Framework; +using System; +using System.Diagnostics; +using System.Drawing.Text; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Windows.Automation; +using System.Windows.Threading; + +namespace VisualTest +{ + public class Class1 + { + private string _assemblyDirectory; + private string _projectDirectory; + private string _exeFilePath; + + private string _assetPath; + + private Process _process; + private IntPtr _hwnd; + + public Class1() + { + var assemblyLocation = Assembly.GetCallingAssembly().Location; + _assemblyDirectory = Path.GetDirectoryName(assemblyLocation); + _projectDirectory = Path.GetDirectoryName(Path.GetDirectoryName(_assemblyDirectory)); + + + var relPath = _assemblyDirectory.Substring(_projectDirectory.Length + 1); + + _assetPath = Path.Combine(_projectDirectory, relPath, "Assets"); + _exeFilePath = Path.Combine(_projectDirectory.Replace("VisualTest", "VisualTestApp"), relPath, "VisualTestApp.exe"); + } + + [SetUp] + public void Setup() + { + _process = Process.Start(_exeFilePath); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (_hwnd == IntPtr.Zero) + { + Thread.Sleep(1000); + _hwnd = _process.MainWindowHandle; + + if (stopwatch.ElapsedMilliseconds > 5000) + throw new InvalidOperationException("Application startup timeout"); + } + } + + + [Test] + public void CheckFileRemove() + { + var mainWindow = AutomationElement.FromHandle(_hwnd); + + var assetPathValPtn = mainWindow.FindPatternById("AssetPathRootTextBox"); + assetPathValPtn.SetValue(_assetPath); + + var markdownValPtn = mainWindow.FindPatternById("MarkdownPathTextBlox"); + markdownValPtn.SetValue("Markdown.txt"); + + // wait for viewing markdown + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var markdownView = mainWindow.FindPatternById("MarkdownScrollViewer"); + while (markdownView.DocumentRange.GetChildren().Length < 4) + { + Thread.Sleep(1000); + + if (stopwatch.ElapsedMilliseconds > 5000) + throw new InvalidOperationException("Markdown drawing timeout"); + } + + Thread.Sleep(1000); + + foreach (var file in Directory.GetFiles(_assetPath)) + { + try + { + TryRemove(file, 1000); + } + catch (Exception e) + { + Assert.Fail($"remove failed: {Path.GetFileName(file)}: {e.Message}"); + } + } + } + + private void TryRemove(string path, long waitTime) + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + for (; ; ) + { + try + { + File.Delete(path); + return; + } + catch + { + if (stopwatch.ElapsedMilliseconds < waitTime) + { + Thread.Sleep(100); + } + else throw; + } + } + } + + + [TearDown] + public void Closing() + { + _process.Kill(); + } + } +} +#endif \ No newline at end of file diff --git a/tests/VisualTest/Utils.cs b/tests/VisualTest/Utils.cs new file mode 100644 index 0000000..45b4441 --- /dev/null +++ b/tests/VisualTest/Utils.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Windows.Automation; + +namespace VisualTest +{ + internal static class Utils + { + public static AutomationElement FindById(this AutomationElement root, string automationId) + => root.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, automationId)); + + public static T FindPatternById(this AutomationElement root, string automationId) + where T : BasePattern + { + var element = FindById(root, automationId); + var pattern = (AutomationPattern)typeof(T).GetField("Pattern").GetValue(null); + + return (T)element.GetCurrentPattern(pattern); + } + + } +} diff --git a/tests/VisualTest/VisualTest.csproj b/tests/VisualTest/VisualTest.csproj new file mode 100644 index 0000000..52d120d --- /dev/null +++ b/tests/VisualTest/VisualTest.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.0;net462;net5.0-windows + true + false + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + OnGitHubAction + + + diff --git a/tests/VisualTestApp/App.xaml b/tests/VisualTestApp/App.xaml new file mode 100644 index 0000000..5290478 --- /dev/null +++ b/tests/VisualTestApp/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/tests/VisualTestApp/App.xaml.cs b/tests/VisualTestApp/App.xaml.cs new file mode 100644 index 0000000..383b0a3 --- /dev/null +++ b/tests/VisualTestApp/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace VisualTestApp +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/tests/VisualTestApp/AssemblyInfo.cs b/tests/VisualTestApp/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/tests/VisualTestApp/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/tests/VisualTestApp/MainWIndowViewModel.cs b/tests/VisualTestApp/MainWIndowViewModel.cs new file mode 100644 index 0000000..1561f49 --- /dev/null +++ b/tests/VisualTestApp/MainWIndowViewModel.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace VisualTestApp +{ + internal class MainWIndowViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + private string _assetPathRoot; + public string AssetPathRoot + { + get => _assetPathRoot; + set + { + _assetPathRoot = value; + var e = new PropertyChangedEventArgs(nameof(AssetPathRoot)); + PropertyChanged?.Invoke(this, e); + } + } + + private string _markdownPath; + public string MarkdownPath { + get => _markdownPath; + set + { + _markdownPath = value; + var e = new PropertyChangedEventArgs(nameof(MarkdownPath)); + PropertyChanged?.Invoke(this, e); + } + } + } +} diff --git a/tests/VisualTestApp/MainWindow.xaml b/tests/VisualTestApp/MainWindow.xaml new file mode 100644 index 0000000..feb5637 --- /dev/null +++ b/tests/VisualTestApp/MainWindow.xaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/VisualTestApp/MainWindow.xaml.cs b/tests/VisualTestApp/MainWindow.xaml.cs new file mode 100644 index 0000000..4ebd4e7 --- /dev/null +++ b/tests/VisualTestApp/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace VisualTestApp +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/tests/VisualTestApp/VisualTestApp.csproj b/tests/VisualTestApp/VisualTestApp.csproj new file mode 100644 index 0000000..c0d0807 --- /dev/null +++ b/tests/VisualTestApp/VisualTestApp.csproj @@ -0,0 +1,15 @@ + + + + WinExe + netcoreapp3.0;net462;net5.0-windows + enable + 9 + true + + + + + + +