├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── config.yml
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── merge-dependabot.yml
│ └── on-push-do-docs.yml
├── .gitignore
├── code_of_conduct.md
├── license.txt
├── readme.md
└── src
├── .editorconfig
├── .gitattributes
├── Directory.Build.props
├── Directory.Packages.props
├── FluentAvaloniaTests
├── CalculatorTests.Render.verified.png
├── CalculatorTests.Render.verified.txt
├── CalculatorTests.cs
├── FluentAvaloniaControlTests.RenderNavigationView.verified.txt
├── FluentAvaloniaControlTests.RenderNavigationViewWithBinding.verified.txt
├── FluentAvaloniaControlTests.RenderNavigationViewWithItemsSource.verified.txt
├── FluentAvaloniaControlTests.cs
├── FluentAvaloniaTests.csproj
├── GlobalUsings.cs
├── ModuleInit.cs
└── TestAppBuilder.cs
├── IncludeThemeVariantTests
├── CalculatorTests.Render#dark.verified.png
├── CalculatorTests.Render#light.verified.png
├── CalculatorTests.Render.verified.txt
├── CalculatorTests.cs
├── GlobalUsings.cs
├── IncludeThemeVariantTests.csproj
└── ModuleInit.cs
├── NUnitTests
├── CalculatorTests.Should_Add_Numbers.verified.png
├── CalculatorTests.Should_Add_Numbers.verified.txt
├── CalculatorTests.cs
├── GlobalUsings.cs
├── ModuleInit.cs
├── MyUserControlTests.Render.verified.png
├── MyUserControlTests.Render.verified.txt
├── MyUserControlTests.cs
├── NUnitTests.csproj
└── TestAppBuilder.cs
├── Shared.sln.DotSettings
├── StandaloneExampleTest.XUnit
├── GlobalUsings.cs
├── StandaloneExampleTest.XUnit.csproj
├── Tests.Test.verified.png
├── Tests.Test.verified.txt
├── Tests.cs
└── VerifyAvaloniaSetupApplication.cs
├── TestableApp
├── App.axaml
├── App.axaml.cs
├── GlobalUsings.cs
├── MainWindow.axaml
├── MainWindow.axaml.cs
├── MainWindowViewModel.cs
├── MyUserControl.axaml
├── MyUserControl.axaml.cs
├── Program.cs
├── RecursiveWindow.axaml
├── RecursiveWindow.axaml.cs
└── TestableApp.csproj
├── Verify.Avalonia.sln
├── Verify.Avalonia.sln.DotSettings
├── Verify.Avalonia
├── Converters
│ ├── AvaloniaConverter.cs
│ ├── CornerRadiusConverter.cs
│ ├── FontFamilyConverter.cs
│ └── ThicknessConverter.cs
├── Extensions.cs
├── GlobalUsings.cs
├── Verify.Avalonia.csproj
├── VerifyAvalonia.cs
└── VerifyAvalonia_Converters.cs
├── XUnitTests
├── CalculatorTests.Should_Add_Numbers.verified.png
├── CalculatorTests.Should_Add_Numbers.verified.txt
├── CalculatorTests.cs
├── GlobalUsings.cs
├── ModuleInit.cs
├── MyUserControlTests.Render.verified.png
├── MyUserControlTests.Render.verified.txt
├── MyUserControlTests.cs
├── TestAppBuilder.cs
├── Tests.Recursive.verified.png
├── Tests.Recursive.verified.txt
├── Tests.cs
└── XUnitTests.csproj
├── appveyor.yml
├── global.json
├── icon.png
├── key.snk
├── mdsnippets.json
└── nuget.config
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: VerifyTests
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug fix
3 | about: Create a bug fix to help us improve
4 | ---
5 |
6 | Note: New issues raised, where it is clear the submitter has not read the issue template, are likely to be closed with "please read the issue template". Please don't take offense at this. It is simply a time management decision. If someone raises an issue, and can't be bothered to spend the time to read the issue template, then the project maintainers should not be expected to spend the time to read the submitted issue. Often too much time is spent going back and forth in issue comments asking for information that is outlined in the issue template.
7 |
8 |
9 | #### Preamble
10 |
11 | General questions may be better placed [StackOveflow](https://stackoverflow.com/).
12 |
13 | Where relevant, ensure you are using the current stable versions on your development stack. For example:
14 |
15 | * Visual Studio
16 | * [.NET SDK or .NET Core SDK](https://www.microsoft.com/net/download)
17 | * Any related NuGet packages
18 |
19 | Any code or stack traces must be properly formatted with [GitHub markdown](https://guides.github.com/features/mastering-markdown/).
20 |
21 |
22 | #### Describe the bug
23 |
24 | A clear and concise description of what the bug is. Include any relevant version information.
25 |
26 | A clear and concise description of what you expected to happen.
27 |
28 | Add any other context about the problem here.
29 |
30 |
31 | #### Minimal Repro
32 |
33 | Ensure you have replicated the bug in a minimal solution with the fewest moving parts. Often this will help point to the true cause of the problem. Upload this repro as part of the issue, preferably a public GitHub repository or a downloadable zip. The repro will allow the maintainers of this project to smoke test the any fix.
34 |
35 | #### Submit a PR that fixes the bug
36 |
37 | Submit a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/) that fixes the bug. Include in this PR a test that verifies the fix. If you were not able to fix the bug, a PR that illustrates your partial progress will suffice.
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: How to raise feature requests
4 | ---
5 |
6 |
7 | Note: New issues raised, where it is clear the submitter has not read the issue template, are likely to be closed with "please read the issue template". Please don't take offense at this. It is simply a time management decision. If someone raises an issue, and can't be bothered to spend the time to read the issue template, then the project maintainers should not be expected to spend the time to read the submitted issue. Often too much time is spent going back and forth in issue comments asking for information that is outlined in the issue template.
8 |
9 | If you are certain the feature will be accepted, it is better to raise a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/).
10 |
11 | If you are uncertain if the feature will be accepted, outline the proposal below to confirm it is viable, prior to raising a PR that implements the feature.
12 |
13 | Note that even if the feature is a good idea and viable, it may not be accepted since the ongoing effort in maintaining the feature may outweigh the benefit it delivers.
14 |
15 |
16 | #### Is the feature request related to a problem
17 |
18 | A clear and concise description of what the problem is.
19 |
20 |
21 | #### Describe the solution
22 |
23 | A clear and concise proposal of how you intend to implement the feature.
24 |
25 |
26 | #### Describe alternatives considered
27 |
28 | A clear and concise description of any alternative solutions or features you've considered.
29 |
30 |
31 | #### Additional context
32 |
33 | Add any other context about the feature request here.
34 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: nuget
4 | directory: "/src"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/.github/workflows/merge-dependabot.yml:
--------------------------------------------------------------------------------
1 | name: merge-dependabot
2 | on:
3 | pull_request:
4 | jobs:
5 | automerge:
6 | runs-on: ubuntu-latest
7 | if: github.actor == 'dependabot[bot]'
8 | steps:
9 | - name: Dependabot Auto Merge
10 | uses: ahmadnassri/action-dependabot-auto-merge@v2.6.6
11 | with:
12 | target: minor
13 | github-token: ${{ secrets.dependabot }}
14 | command: squash and merge
--------------------------------------------------------------------------------
/.github/workflows/on-push-do-docs.yml:
--------------------------------------------------------------------------------
1 | name: on-push-do-docs
2 | on:
3 | push:
4 | jobs:
5 | docs:
6 | runs-on: windows-latest
7 | steps:
8 | - uses: actions/checkout@v4
9 | - name: Run MarkdownSnippets
10 | run: |
11 | dotnet tool install --global MarkdownSnippets.Tool
12 | mdsnippets ${GITHUB_WORKSPACE}
13 | shell: bash
14 | - name: Push changes
15 | run: |
16 | git config --local user.email "action@github.com"
17 | git config --local user.name "GitHub Action"
18 | git commit -m "Docs changes" -a || echo "nothing to commit"
19 | remote="https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git"
20 | branch="${GITHUB_REF:11}"
21 | git push "${remote}" ${branch} || echo "nothing to push"
22 | shell: bash
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.suo
2 | *.user
3 | bin/
4 | obj/
5 | .vs/
6 | *.DotSettings.user
7 | .idea/
8 | *.received.*
9 | nugets/
--------------------------------------------------------------------------------
/code_of_conduct.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This project has adopted the code of conduct defined by the Contributor Covenant
4 | to clarify expected behavior in our community.
5 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/about/code-of-conduct).
6 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) .NET Foundation and Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | #
Verify.Avalonia
2 |
3 | [](https://github.com/orgs/VerifyTests/discussions)
4 | [](https://ci.appveyor.com/project/SimonCropp/verify-avalonia)
5 | [](https://www.nuget.org/packages/Verify.Avalonia/)
6 |
7 | Extends [Verify](https://github.com/VerifyTests/Verify) to allow verification of [Avalonia UIs](https://avaloniaui.net/).
8 |
9 |
10 | ## Getting Started
11 |
12 | The test project needs a `ModuleInitializer` and an Avalonia application with a `Style`.
13 |
14 |
15 |
16 | ```cs
17 | [assembly: AvaloniaTestApplication(typeof(VerifyAvaloniaSetupApplication))]
18 |
19 | public class VerifyAvaloniaSetupApplication : Application
20 | {
21 | [ModuleInitializer]
22 | public static void Init()
23 | {
24 | VerifyImageMagick.RegisterComparers(.24);
25 | VerifierSettings.InitializePlugins();
26 | }
27 |
28 | public static AppBuilder BuildAvaloniaApp() =>
29 | AppBuilder
30 | .Configure()
31 | .UseSkia()
32 | .UseHeadless(
33 | new()
34 | {
35 | UseHeadlessDrawing = false
36 | });
37 |
38 | public VerifyAvaloniaSetupApplication() =>
39 | Styles.Add(new FluentTheme());
40 | }
41 | ```
42 | snippet source | anchor
43 |
44 |
45 | And add the following NuGet packages:
46 |
47 | - https://nuget.org/packages/Verify.Avalonia/
48 | - https://nuget.org/packages/Avalonia.Headless.XUnit/
49 | - https://nuget.org/packages/Avalonia.Themes.Fluent/
50 | - https://nuget.org/packages/Avalonia.Skia/
51 |
52 |
53 | ## More details
54 |
55 | **See [Milestones](../../milestones?state=closed) for release notes.**
56 |
57 | Leverages [Avalonia Headless Testing](https://docs.avaloniaui.net/docs/next/concepts/headless).
58 |
59 | See [Headless Testing with XUnit](https://docs.avaloniaui.net/docs/next/concepts/headless/headless-xunit) and [Headless Testing with NUnit](https://docs.avaloniaui.net/docs/next/concepts/headless/headless-nunit) for more information.
60 |
61 |
62 | ### ModuleInitializer
63 |
64 |
65 |
66 | ```cs
67 | [ModuleInitializer]
68 | public static void Init()
69 | {
70 | VerifyImageMagick.RegisterComparers(0.17);
71 | VerifyAvalonia.Initialize();
72 | }
73 | ```
74 | snippet source | anchor
75 |
76 |
77 | This sample uses [Verify.ImageMagick](https://github.com/VerifyTests/Verify.ImageMagick) to ignore small rendering differences that are expected between different operating systems.
78 |
79 | Other [comparers](https://github.com/VerifyTests/Verify/blob/main/docs/comparer.md) options:
80 |
81 | * https://github.com/VerifyTests/Verify.ImageHash
82 | * https://github.com/VerifyTests/Verify.ImageMagick
83 | * https://github.com/VerifyTests/Verify.Phash
84 | * https://github.com/VerifyTests/Verify.ImageSharp.Compare
85 |
86 |
87 | ### Verify.CommunityToolkit.Mvvm
88 |
89 | Many Avalonia projects use [CommunityToolkit.Mvvm](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/). To ensure proper serialization of MVVM commands, use [Verify.CommunityToolkit.Mvvm](https://github.com/VerifyTests/Verify.CommunityToolkit.Mvvm).
90 |
91 |
92 | ### InternalsVisibleTo
93 |
94 | Ensure tests projects have InternalsVisibleTo configured in the target app so tests can use generated controls by name.
95 |
96 |
97 |
98 | ```csproj
99 |
100 |
101 |
102 |
103 | ```
104 | snippet source | anchor
105 |
106 |
107 |
108 | ### Initialize AvaloniaTestApplication
109 |
110 | The `[AvaloniaTestApplication]` attribute wires the tests in the current project with the specific application. It needs to be defined once per project in any file. Verify.Avalonia requires that `UseHeadlessDrawing` is disabled and `.UseSkia()` is set.
111 |
112 |
113 |
114 | ```cs
115 | [assembly: AvaloniaTestApplication(typeof(TestAppBuilder))]
116 |
117 | public static class TestAppBuilder
118 | {
119 | public static AppBuilder BuildAvaloniaApp() =>
120 | AppBuilder.Configure()
121 | .UseSkia()
122 | .UseHeadless(
123 | new()
124 | {
125 | UseHeadlessDrawing = false
126 | });
127 | }
128 | ```
129 | snippet source | anchor
130 |
131 |
132 |
133 | ### Window Test
134 |
135 |
136 |
137 | ```cs
138 | public class CalculatorTests
139 | {
140 | [AvaloniaFact]
141 | public Task Should_Add_Numbers()
142 | {
143 | var window = new MainWindow
144 | {
145 | DataContext = new MainWindowViewModel()
146 | };
147 |
148 | window.Show();
149 |
150 | // Set values to the input boxes
151 | window.FirstOperandInput.Text = "10";
152 | window.SecondOperandInput.Text = "20";
153 |
154 | // Raise click event on the button:
155 | window.AddButton.Focus();
156 | window.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None);
157 |
158 | Assert.Equal("30", window.ResultBox.Text);
159 | return Verify(window);
160 | }
161 | }
162 | ```
163 | snippet source | anchor
164 |
165 |
166 |
167 | ### Result in the following snapshots
168 |
169 |
170 | #### Image
171 |
172 | [Should_Add_Numbers.verified.verified.png](/src/XUnitTests/CalculatorTests.Should_Add_Numbers.verified.png):
173 |
174 |
175 |
176 |
177 | #### Text
178 |
179 |
180 |
181 | ```txt
182 | {
183 | Type: MainWindow,
184 | SizeToContent: WidthAndHeight,
185 | Title: Simple Calculator,
186 | CanResize: false,
187 | Content: {
188 | Type: StackPanel,
189 | Spacing: 10.0,
190 | Width: 280.0,
191 | Height: 175.0,
192 | Margin: 10,
193 | HorizontalAlignment: Left,
194 | Children: [
195 | {
196 | Type: TextBox,
197 | Text: 10,
198 | Watermark: Operand 1,
199 | Name: FirstOperandInput
200 | },
201 | {
202 | Type: TextBox,
203 | Text: 20,
204 | Watermark: Operand 2,
205 | Name: SecondOperandInput
206 | },
207 | {
208 | Type: UniformGrid,
209 | Columns: 4,
210 | Children: [
211 | {
212 | Type: Button,
213 | Command: MainWindowViewModel.Add,
214 | Content: +,
215 | Name: AddButton
216 | },
217 | {
218 | Type: Button,
219 | Command: MainWindowViewModel.Subtract,
220 | Content: -,
221 | Name: SubtractButton
222 | },
223 | {
224 | Type: Button,
225 | Command: MainWindowViewModel.Multiply,
226 | Content: *,
227 | Name: MultiplyButton
228 | },
229 | {
230 | Type: Button,
231 | Command: MainWindowViewModel.Divide,
232 | Content: /,
233 | Name: DivideButton
234 | }
235 | ]
236 | },
237 | {
238 | Type: StackPanel,
239 | Spacing: 10.0,
240 | Orientation: Horizontal,
241 | Children: [
242 | {
243 | Type: TextBlock,
244 | Text: Result:
245 | },
246 | {
247 | Type: TextBlock,
248 | Text: 30,
249 | Name: ResultBox
250 | }
251 | ]
252 | }
253 | ]
254 | },
255 | Background: LightGray,
256 | Width: 300.0,
257 | Height: 195.0,
258 | IsVisible: true,
259 | DataContext: {
260 | FirstOperand: 10.0,
261 | SecondOperand: 20.0,
262 | Result: 30,
263 | AddCommand: MainWindowViewModel.Add,
264 | SubtractCommand: MainWindowViewModel.Subtract,
265 | MultiplyCommand: MainWindowViewModel.Multiply,
266 | DivideCommand: MainWindowViewModel.Divide
267 | }
268 | }
269 | ```
270 | snippet source | anchor
271 |
272 |
273 |
274 | ### UserControl Test
275 |
276 | Given the control:
277 |
278 |
279 |
280 | ```axaml
281 |
287 |
288 |
289 |
290 |
291 |
292 | ```
293 | snippet source | anchor
294 |
295 |
296 | And the test:
297 |
298 |
299 |
300 | ```cs
301 | public class MyUserControlTests
302 | {
303 | [AvaloniaFact]
304 | public Task Render()
305 | {
306 | var control = new MyUserControl();
307 | return Verify(control);
308 | }
309 | }
310 | ```
311 | snippet source | anchor
312 |
313 |
314 |
315 | ### Result in the following snapshots
316 |
317 |
318 | #### Image
319 |
320 | [Should_Add_Numbers.verified.verified.png](/src/XUnitTests/MyUserControlTests.Render.verified.png):
321 |
322 |
323 |
324 |
325 | #### Text
326 |
327 |
328 |
329 | ```txt
330 | {
331 | Type: MyUserControl,
332 | Content: {
333 | Type: StackPanel,
334 | Spacing: 10.0,
335 | Orientation: Vertical,
336 | Margin: 10,
337 | HorizontalAlignment: Left,
338 | Children: [
339 | {
340 | Type: TextBlock,
341 | Text: Welcome to Avalonia!
342 | },
343 | {
344 | Type: Button,
345 | Content: Button
346 | }
347 | ]
348 | },
349 | Background: LightGray,
350 | Width: 200.0,
351 | Height: 100.0
352 | }
353 | ```
354 | snippet source | anchor
355 |
356 |
357 |
358 | ## IncludeThemeVariant
359 |
360 | The `VerifyAvalonia.IncludeThemeVariant()` method is used to include both `ThemeVariant.Light` and `ThemeVariant.Dark` variants when rendering UIs.
361 |
362 |
363 |
364 | ```cs
365 | [ModuleInitializer]
366 | public static void Init()
367 | {
368 | VerifyAvalonia.IncludeThemeVariant();
369 | VerifierSettings.InitializePlugins();
370 | }
371 | ```
372 | snippet source | anchor
373 |
374 |
375 | Then given the same `CalculatorTests` will produce the `verified.txt` as above, but will now produce two pngs, the first for `ThemeVariant.Light` and the second for `ThemeVariant.Dark`:
376 |
377 |
378 |
379 |
380 |
381 | ## Additional Control Libraries
382 |
383 | The `VerifyAvalonia.AddAvaloniaConvertersForAssembly` method is used to include converters for additional control assemblies.
384 |
385 |
386 |
387 | ```cs
388 | [ModuleInitializer]
389 | public static void Init()
390 | {
391 | // FluentAvalonia
392 | VerifyAvalonia.AddAvaloniaConvertersForAssemblyOfType();
393 | VerifyImageMagick.RegisterComparers(0.17);
394 | VerifierSettings.InitializePlugins();
395 | }
396 | ```
397 | snippet source | anchor
398 |
399 |
--------------------------------------------------------------------------------
/src/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 |
6 | [*.cs]
7 | indent_size = 4
8 | charset = utf-8
9 |
10 | # Redundant accessor body
11 | resharper_redundant_accessor_body_highlighting = error
12 |
13 | # Replace with field keyword
14 | resharper_replace_with_field_keyword_highlighting = error
15 |
16 | # Replace with single call to Single(..)
17 | resharper_replace_with_single_call_to_single_highlighting = error
18 |
19 | # Replace with single call to SingleOrDefault(..)
20 | resharper_replace_with_single_call_to_single_or_default_highlighting = error
21 |
22 | # Replace with single call to LastOrDefault(..)
23 | resharper_replace_with_single_call_to_last_or_default_highlighting = error
24 |
25 | # Replace with single call to Last(..)
26 | resharper_replace_with_single_call_to_last_highlighting = error
27 |
28 | # Replace with single call to First(..)
29 | resharper_replace_with_single_call_to_first_highlighting = error
30 |
31 | # Replace with single call to FirstOrDefault(..)
32 | resharper_replace_with_single_call_to_first_or_default_highlighting = error
33 |
34 | # Replace with single call to Any(..)
35 | resharper_replace_with_single_call_to_any_highlighting = error
36 |
37 | # Replace with single call to Count(..)
38 | resharper_replace_with_single_call_to_count_highlighting = error
39 |
40 | # Declare types in namespaces
41 | dotnet_diagnostic.CA1050.severity = none
42 |
43 | # Use Literals Where Appropriate
44 | dotnet_diagnostic.CA1802.severity = error
45 |
46 | # Template should be a static expression
47 | dotnet_diagnostic.CA2254.severity = error
48 |
49 | # Potentially misleading parameter name in lambda or local function
50 | resharper_all_underscore_local_parameter_name_highlighting = none
51 |
52 | # Redundant explicit collection creation in argument of 'params' parameter
53 | resharper_redundant_explicit_params_array_creation_highlighting = error
54 |
55 | # Do not initialize unnecessarily
56 | dotnet_diagnostic.CA1805.severity = error
57 |
58 | # Avoid unsealed attributes
59 | dotnet_diagnostic.CA1813.severity = error
60 |
61 | # Test for empty strings using string length
62 | dotnet_diagnostic.CA1820.severity = none
63 |
64 | # Remove empty finalizers
65 | dotnet_diagnostic.CA1821.severity = error
66 |
67 | # Mark members as static
68 | dotnet_diagnostic.CA1822.severity = error
69 |
70 | # Avoid unused private fields
71 | dotnet_diagnostic.CA1823.severity = error
72 |
73 | # Avoid zero-length array allocations
74 | dotnet_diagnostic.CA1825.severity = error
75 |
76 | # Use property instead of Linq Enumerable method
77 | dotnet_diagnostic.CA1826.severity = error
78 |
79 | # Do not use Count()/LongCount() when Any() can be used
80 | dotnet_diagnostic.CA1827.severity = error
81 | dotnet_diagnostic.CA1828.severity = error
82 |
83 | # Use Length/Count property instead of Enumerable.Count method
84 | dotnet_diagnostic.CA1829.severity = error
85 |
86 | # Prefer strongly-typed Append and Insert method overloads on StringBuilder
87 | dotnet_diagnostic.CA1830.severity = error
88 |
89 | # Use AsSpan instead of Range-based indexers for string when appropriate
90 | dotnet_diagnostic.CA1831.severity = error
91 |
92 | # Use AsSpan instead of Range-based indexers for string when appropriate
93 | dotnet_diagnostic.CA1831.severity = error
94 | dotnet_diagnostic.CA1832.severity = error
95 | dotnet_diagnostic.CA1833.severity = error
96 |
97 | # Use StringBuilder.Append(char) for single character strings
98 | dotnet_diagnostic.CA1834.severity = error
99 |
100 | # Prefer IsEmpty over Count when available
101 | dotnet_diagnostic.CA1836.severity = error
102 |
103 | # Prefer IsEmpty over Count when available
104 | dotnet_diagnostic.CA1836.severity = error
105 |
106 | # Use Environment.ProcessId instead of Process.GetCurrentProcess().Id
107 | dotnet_diagnostic.CA1837.severity = error
108 |
109 | # Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName
110 | dotnet_diagnostic.CA1839.severity = error
111 |
112 | # Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId
113 | dotnet_diagnostic.CA1840.severity = error
114 |
115 | # Prefer Dictionary Contains methods
116 | dotnet_diagnostic.CA1841.severity = error
117 |
118 | # Do not use WhenAll with a single task
119 | dotnet_diagnostic.CA1842.severity = error
120 |
121 | # Do not use WhenAll/WaitAll with a single task
122 | dotnet_diagnostic.CA1842.severity = error
123 | dotnet_diagnostic.CA1843.severity = error
124 |
125 | # Use span-based 'string.Concat'
126 | dotnet_diagnostic.CA1845.severity = error
127 |
128 | # Prefer AsSpan over Substring
129 | dotnet_diagnostic.CA1846.severity = error
130 |
131 | # Use string.Contains(char) instead of string.Contains(string) with single characters
132 | dotnet_diagnostic.CA1847.severity = error
133 |
134 | # Prefer static HashData method over ComputeHash
135 | dotnet_diagnostic.CA1850.severity = error
136 |
137 | # Possible multiple enumerations of IEnumerable collection
138 | dotnet_diagnostic.CA1851.severity = error
139 |
140 | # Unnecessary call to Dictionary.ContainsKey(key)
141 | dotnet_diagnostic.CA1853.severity = error
142 |
143 | # Prefer the IDictionary.TryGetValue(TKey, out TValue) method
144 | dotnet_diagnostic.CA1854.severity = error
145 |
146 | # Use Span.Clear() instead of Span.Fill()
147 | dotnet_diagnostic.CA1855.severity = error
148 |
149 | # Incorrect usage of ConstantExpected attribute
150 | dotnet_diagnostic.CA1856.severity = error
151 |
152 | # The parameter expects a constant for optimal performance
153 | dotnet_diagnostic.CA1857.severity = error
154 |
155 | # Use StartsWith instead of IndexOf
156 | dotnet_diagnostic.CA1858.severity = error
157 |
158 | # Avoid using Enumerable.Any() extension method
159 | dotnet_diagnostic.CA1860.severity = error
160 |
161 | # Avoid constant arrays as arguments
162 | dotnet_diagnostic.CA1861.severity = error
163 |
164 | # Use the StringComparison method overloads to perform case-insensitive string comparisons
165 | dotnet_diagnostic.CA1862.severity = error
166 |
167 | # Prefer the IDictionary.TryAdd(TKey, TValue) method
168 | dotnet_diagnostic.CA1864.severity = error
169 |
170 | # Use string.Method(char) instead of string.Method(string) for string with single char
171 | dotnet_diagnostic.CA1865.severity = error
172 | dotnet_diagnostic.CA1866.severity = error
173 | dotnet_diagnostic.CA1867.severity = error
174 |
175 | # Unnecessary call to 'Contains' for sets
176 | dotnet_diagnostic.CA1868.severity = error
177 |
178 | # Cache and reuse 'JsonSerializerOptions' instances
179 | dotnet_diagnostic.CA1869.severity = error
180 |
181 | # Use a cached 'SearchValues' instance
182 | dotnet_diagnostic.CA1870.severity = error
183 |
184 | # Microsoft .NET properties
185 | trim_trailing_whitespace = true
186 | csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion
187 | resharper_namespace_body = file_scoped
188 | dotnet_naming_rule.private_constants_rule.severity = warning
189 | dotnet_naming_rule.private_constants_rule.style = lower_camel_case_style
190 | dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
191 | dotnet_naming_rule.private_instance_fields_rule.severity = warning
192 | dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
193 | dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
194 | dotnet_naming_rule.private_static_fields_rule.severity = warning
195 | dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
196 | dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
197 | dotnet_naming_rule.private_static_readonly_rule.severity = warning
198 | dotnet_naming_rule.private_static_readonly_rule.style = lower_camel_case_style
199 | dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
200 | dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
201 | dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
202 | dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
203 | dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
204 | dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
205 | dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
206 | dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
207 | dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
208 | dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
209 | dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
210 | dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
211 | dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
212 | dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly
213 | dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
214 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
215 | dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
216 |
217 | # ReSharper properties
218 | resharper_object_creation_when_type_not_evident = target_typed
219 |
220 | # ReSharper inspection severities
221 | resharper_arrange_object_creation_when_type_evident_highlighting = error
222 | resharper_arrange_object_creation_when_type_not_evident_highlighting = error
223 | resharper_arrange_redundant_parentheses_highlighting = error
224 | resharper_arrange_static_member_qualifier_highlighting = error
225 | resharper_arrange_this_qualifier_highlighting = error
226 | resharper_arrange_type_member_modifiers_highlighting = none
227 | resharper_built_in_type_reference_style_for_member_access_highlighting = hint
228 | resharper_built_in_type_reference_style_highlighting = hint
229 | resharper_check_namespace_highlighting = none
230 | resharper_convert_to_using_declaration_highlighting = error
231 | resharper_css_not_resolved_highlighting = warning
232 | resharper_field_can_be_made_read_only_local_highlighting = none
233 | resharper_merge_into_logical_pattern_highlighting = warning
234 | resharper_merge_into_pattern_highlighting = error
235 | resharper_method_has_async_overload_highlighting = warning
236 | # because stop rider giving errors before source generators have run
237 | resharper_partial_type_with_single_part_highlighting = warning
238 | resharper_redundant_base_qualifier_highlighting = warning
239 | resharper_redundant_cast_highlighting = error
240 | resharper_redundant_empty_object_creation_argument_list_highlighting = error
241 | resharper_redundant_empty_object_or_collection_initializer_highlighting = error
242 | resharper_redundant_name_qualifier_highlighting = error
243 | resharper_redundant_suppress_nullable_warning_expression_highlighting = error
244 | resharper_redundant_using_directive_highlighting = error
245 | resharper_redundant_verbatim_string_prefix_highlighting = error
246 | resharper_redundant_lambda_signature_parentheses_highlighting = error
247 | resharper_replace_substring_with_range_indexer_highlighting = warning
248 | resharper_suggest_var_or_type_built_in_types_highlighting = error
249 | resharper_suggest_var_or_type_elsewhere_highlighting = error
250 | resharper_suggest_var_or_type_simple_types_highlighting = error
251 | resharper_unnecessary_whitespace_highlighting = error
252 | resharper_use_await_using_highlighting = warning
253 | resharper_use_deconstruction_highlighting = warning
254 |
255 | # Sort using and Import directives with System.* appearing first
256 | dotnet_sort_system_directives_first = true
257 |
258 | # Avoid "this." and "Me." if not necessary
259 | dotnet_style_qualification_for_field = false:error
260 | dotnet_style_qualification_for_property = false:error
261 | dotnet_style_qualification_for_method = false:error
262 | dotnet_style_qualification_for_event = false:error
263 |
264 | # Use language keywords instead of framework type names for type references
265 | dotnet_style_predefined_type_for_locals_parameters_members = true:error
266 | dotnet_style_predefined_type_for_member_access = true:error
267 |
268 | # Suggest more modern language features when available
269 | dotnet_style_object_initializer = true:error
270 | dotnet_style_collection_initializer = true:error
271 | dotnet_style_coalesce_expression = false:error
272 | dotnet_style_null_propagation = true:error
273 | dotnet_style_explicit_tuple_names = true:error
274 |
275 | # Use collection expression syntax
276 | resharper_use_collection_expression_highlighting = error
277 |
278 | # Prefer "var" everywhere
279 | csharp_style_var_for_built_in_types = true:error
280 | csharp_style_var_when_type_is_apparent = true:error
281 | csharp_style_var_elsewhere = true:error
282 |
283 | # Prefer method-like constructs to have a block body
284 | csharp_style_expression_bodied_methods = true:error
285 | csharp_style_expression_bodied_local_functions = true:error
286 | csharp_style_expression_bodied_constructors = true:error
287 | csharp_style_expression_bodied_operators = true:error
288 | resharper_place_expr_method_on_single_line = false
289 |
290 | # Prefer property-like constructs to have an expression-body
291 | csharp_style_expression_bodied_properties = true:error
292 | csharp_style_expression_bodied_indexers = true:error
293 | csharp_style_expression_bodied_accessors = true:error
294 |
295 | # Suggest more modern language features when available
296 | csharp_style_pattern_matching_over_is_with_cast_check = true:error
297 | csharp_style_pattern_matching_over_as_with_null_check = true:error
298 | csharp_style_inlined_variable_declaration = true:suggestion
299 | csharp_style_throw_expression = true:suggestion
300 | csharp_style_conditional_delegate_call = true:suggestion
301 |
302 | # Newline settings
303 | #csharp_new_line_before_open_brace = all:error
304 | resharper_max_array_initializer_elements_on_line = 1
305 | csharp_new_line_before_else = true
306 | csharp_new_line_before_catch = true
307 | csharp_new_line_before_finally = true
308 | csharp_new_line_before_members_in_object_initializers = true
309 | csharp_new_line_before_members_in_anonymous_types = true
310 | resharper_wrap_before_first_type_parameter_constraint = true
311 | resharper_wrap_extends_list_style = chop_always
312 | resharper_wrap_after_dot_in_method_calls = false
313 | resharper_wrap_before_binary_pattern_op = false
314 | resharper_wrap_object_and_collection_initializer_style = chop_always
315 | resharper_place_simple_initializer_on_single_line = false
316 |
317 | # space
318 | resharper_space_around_lambda_arrow = true
319 |
320 | dotnet_style_require_accessibility_modifiers = never:error
321 | resharper_place_type_constraints_on_same_line = false
322 | resharper_blank_lines_inside_namespace = 0
323 | resharper_blank_lines_after_file_scoped_namespace_directive = 1
324 | resharper_blank_lines_inside_type = 0
325 |
326 | insert_final_newline = false
327 | resharper_place_attribute_on_same_line = false
328 | resharper_space_around_lambda_arrow = true
329 | resharper_place_constructor_initializer_on_same_line = false
330 |
331 | #braces https://www.jetbrains.com/help/resharper/EditorConfig_CSHARP_CSharpCodeStylePageImplSchema.html#Braces
332 | resharper_braces_for_ifelse = required
333 | resharper_braces_for_foreach = required
334 | resharper_braces_for_while = required
335 | resharper_braces_for_dowhile = required
336 | resharper_braces_for_lock = required
337 | resharper_braces_for_fixed = required
338 | resharper_braces_for_for = required
339 |
340 | resharper_return_value_of_pure_method_is_not_used_highlighting = error
341 |
342 | resharper_all_underscore_local_parameter_name_highlighting = none
343 |
344 | resharper_misleading_body_like_statement_highlighting = error
345 |
346 | resharper_redundant_record_class_keyword_highlighting = error
347 |
348 | resharper_redundant_extends_list_entry_highlighting = error
349 |
350 | # Xml files
351 | [*.{xml,config,nuspec,resx,vsixmanifest,csproj,targets,props,fsproj}]
352 | indent_size = 2
353 | # https://www.jetbrains.com/help/resharper/EditorConfig_XML_XmlCodeStylePageSchema.html#resharper_xml_blank_line_after_pi
354 | resharper_blank_line_after_pi = false
355 | resharper_space_before_self_closing = true
356 | ij_xml_space_inside_empty_tag = true
357 |
358 | [*.json]
359 | indent_size = 2
360 |
361 | # Verify settings
362 | [*.{received,verified}.{txt,xml,json,md,sql,csv,html,htm,md}]
363 | charset = utf-8-bom
364 | end_of_line = lf
365 | indent_size = unset
366 | indent_style = unset
367 | insert_final_newline = false
368 | tab_width = unset
369 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/src/.gitattributes:
--------------------------------------------------------------------------------
1 | * text
2 | *.snk binary
3 | *.png binary
4 |
5 | *.verified.txt text eol=lf working-tree-encoding=UTF-8
6 | *.verified.xml text eol=lf working-tree-encoding=UTF-8
7 | *.verified.json text eol=lf working-tree-encoding=UTF-8
8 |
9 | .editorconfig text eol=lf working-tree-encoding=UTF-8
10 | Shared.sln.DotSettings text eol=lf working-tree-encoding=UTF-8
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | preview
5 | CS1591;CS0649;CS8632;CA1416;NU1608;NU1109
6 | 1.4.0
7 | 1.0.0
8 | Avalonia, Verify
9 | enable
10 | Extends Verify (https://github.com/VerifyTests/Verify) to allow verification of Avalonia bits.
11 | true
12 | true
13 | true
14 | true
15 |
16 |
--------------------------------------------------------------------------------
/src/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/CalculatorTests.Render.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/FluentAvaloniaTests/CalculatorTests.Render.verified.png
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/CalculatorTests.Render.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MainWindow,
3 | SizeToContent: WidthAndHeight,
4 | Title: Simple Calculator,
5 | CanResize: false,
6 | Content: {
7 | Type: StackPanel,
8 | Spacing: 10.0,
9 | Width: 280.0,
10 | Height: 175.0,
11 | Margin: 10,
12 | HorizontalAlignment: Left,
13 | Children: [
14 | {
15 | Type: TextBox,
16 | Watermark: Operand 1,
17 | Name: FirstOperandInput
18 | },
19 | {
20 | Type: TextBox,
21 | Watermark: Operand 2,
22 | Name: SecondOperandInput
23 | },
24 | {
25 | Type: UniformGrid,
26 | Columns: 4,
27 | Children: [
28 | {
29 | Type: Button,
30 | Command: MainWindowViewModel.Add,
31 | Content: +,
32 | Name: AddButton
33 | },
34 | {
35 | Type: Button,
36 | Command: MainWindowViewModel.Subtract,
37 | Content: -,
38 | Name: SubtractButton
39 | },
40 | {
41 | Type: Button,
42 | Command: MainWindowViewModel.Multiply,
43 | Content: *,
44 | Name: MultiplyButton
45 | },
46 | {
47 | Type: Button,
48 | Command: MainWindowViewModel.Divide,
49 | Content: /,
50 | Name: DivideButton
51 | }
52 | ]
53 | },
54 | {
55 | Type: StackPanel,
56 | Spacing: 10.0,
57 | Orientation: Horizontal,
58 | Children: [
59 | {
60 | Type: TextBlock,
61 | Text: Result:
62 | },
63 | {
64 | Type: TextBlock,
65 | Name: ResultBox
66 | }
67 | ]
68 | }
69 | ]
70 | },
71 | Background: LightGray,
72 | Width: 300.0,
73 | Height: 195.0,
74 | IsVisible: true,
75 | DataContext: {
76 | AddCommand: MainWindowViewModel.Add,
77 | SubtractCommand: MainWindowViewModel.Subtract,
78 | MultiplyCommand: MainWindowViewModel.Multiply,
79 | DivideCommand: MainWindowViewModel.Divide
80 | }
81 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/CalculatorTests.cs:
--------------------------------------------------------------------------------
1 | [TestFixture]
2 | public class CalculatorTests
3 | {
4 | [AvaloniaTest]
5 | public Task Render()
6 | {
7 | var window = new MainWindow
8 | {
9 | DataContext = new MainWindowViewModel()
10 | };
11 |
12 | return Verify(window);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/FluentAvaloniaControlTests.RenderNavigationView.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: NavigationView,
3 | IsSettingsVisible: true,
4 | PaneDisplayMode: LeftCompact,
5 | TemplateSettings: {
6 | Type: NavigationViewTemplateSettings,
7 | LeftPaneVisibility: true,
8 | PaneToggleButtonVisibility: true,
9 | PaneToggleButtonWidth: 48.0,
10 | SmallerPaneToggleButtonWidth: 40.0,
11 | TopPaneVisibility: false
12 | },
13 | Header: {
14 | Type: TextBlock,
15 | Text: The Header
16 | },
17 | Content: This is the content!
18 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/FluentAvaloniaControlTests.RenderNavigationViewWithBinding.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: NavigationView,
3 | IsSettingsVisible: true,
4 | MenuItemsSource: [
5 | 1 Nav Item,
6 | 2 Nav Item,
7 | 3 Nav Item
8 | ],
9 | PaneDisplayMode: LeftCompact,
10 | TemplateSettings: {
11 | Type: NavigationViewTemplateSettings,
12 | LeftPaneVisibility: true,
13 | PaneToggleButtonVisibility: true,
14 | PaneToggleButtonWidth: 48.0,
15 | SmallerPaneToggleButtonWidth: 40.0,
16 | TopPaneVisibility: false
17 | },
18 | Header: {
19 | Type: TextBlock,
20 | Text: The Header
21 | },
22 | Content: This is the content!,
23 | DataContext: [
24 | 1 Nav Item,
25 | 2 Nav Item,
26 | 3 Nav Item
27 | ]
28 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/FluentAvaloniaControlTests.RenderNavigationViewWithItemsSource.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: NavigationView,
3 | IsSettingsVisible: true,
4 | MenuItemsSource: [
5 | 1 Nav Item,
6 | 2 Nav Item,
7 | 3 Nav Item
8 | ],
9 | PaneDisplayMode: LeftCompact,
10 | TemplateSettings: {
11 | Type: NavigationViewTemplateSettings,
12 | LeftPaneVisibility: true,
13 | PaneToggleButtonVisibility: true,
14 | PaneToggleButtonWidth: 48.0,
15 | SmallerPaneToggleButtonWidth: 40.0,
16 | TopPaneVisibility: false
17 | },
18 | Header: {
19 | Type: TextBlock,
20 | Text: The Header
21 | },
22 | Content: This is the content!
23 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/FluentAvaloniaControlTests.cs:
--------------------------------------------------------------------------------
1 | [TestFixture]
2 | public class FluentAvaloniaControlTests
3 | {
4 | [AvaloniaTest]
5 | public Task RenderNavigationView()
6 | {
7 | var control = new NavigationView
8 | {
9 | PaneDisplayMode = NavigationViewPaneDisplayMode.LeftCompact,
10 | IsSettingsVisible = true,
11 | Header = new TextBlock
12 | {
13 | Text = "The Header"
14 | },
15 | MenuItems =
16 | [
17 | new NavigationViewItem
18 | {
19 | Content = "1 Nav Item"
20 | },
21 | new NavigationViewItem
22 | {
23 | Content = "2 Nav Item",
24 | IconSource = new SymbolIconSource
25 | {
26 | Symbol = Symbol.Admin
27 | }
28 | },
29 | new NavigationViewItem
30 | {
31 | Content = "3 Nav Item"
32 | },
33 | ],
34 | Content = "This is the content!",
35 | };
36 | return Verify(control);
37 | }
38 |
39 | [AvaloniaTest]
40 | public Task RenderNavigationViewWithItemsSource()
41 | {
42 | string[] itemsSource = ["1 Nav Item", "2 Nav Item", "3 Nav Item"];
43 | var control = new NavigationView
44 | {
45 | PaneDisplayMode = NavigationViewPaneDisplayMode.LeftCompact,
46 | IsSettingsVisible = true,
47 | Header = new TextBlock
48 | {
49 | Text = "The Header"
50 | },
51 | MenuItemsSource = itemsSource,
52 | Content = "This is the content!",
53 | };
54 | return Verify(control);
55 | }
56 |
57 | [AvaloniaTest]
58 | public Task RenderNavigationViewWithBinding()
59 | {
60 | string[] itemsSource = ["1 Nav Item", "2 Nav Item", "3 Nav Item"];
61 | var control = new NavigationView
62 | {
63 | PaneDisplayMode = NavigationViewPaneDisplayMode.LeftCompact,
64 | IsSettingsVisible = true,
65 | Header = new TextBlock
66 | {
67 | Text = "The Header"
68 | },
69 | [!NavigationView.MenuItemsSourceProperty] = new Binding(""),
70 | Content = "This is the content!",
71 | DataContext = itemsSource,
72 | };
73 | return Verify(control);
74 | }
75 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/FluentAvaloniaTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using Avalonia;
2 | global using Avalonia.Controls;
3 | global using Avalonia.Data;
4 | global using Avalonia.Headless;
5 | global using Avalonia.Headless.NUnit;
6 | global using FluentAvalonia.Styling;
7 | global using FluentAvalonia.UI.Controls;
8 | global using TestableApp;
9 |
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/ModuleInit.cs:
--------------------------------------------------------------------------------
1 | public static class ModuleInit
2 | {
3 | #region InitAddAvaloniaConvertersForAssembly
4 |
5 | [ModuleInitializer]
6 | public static void Init()
7 | {
8 | // FluentAvalonia
9 | VerifyAvalonia.AddAvaloniaConvertersForAssemblyOfType();
10 | VerifyImageMagick.RegisterComparers(0.17);
11 | VerifierSettings.InitializePlugins();
12 | }
13 |
14 | #endregion
15 | }
--------------------------------------------------------------------------------
/src/FluentAvaloniaTests/TestAppBuilder.cs:
--------------------------------------------------------------------------------
1 | [assembly: AvaloniaTestApplication(typeof(TestAppBuilder))]
2 |
3 | public static class TestAppBuilder
4 | {
5 | public static AppBuilder BuildAvaloniaApp() =>
6 | AppBuilder.Configure()
7 | .UseSkia()
8 | .UseHeadless(new () { UseHeadlessDrawing = false })
9 | .AfterSetup(builder =>
10 | {
11 | if (builder.Instance is null)
12 | throw new ("Instance is null");
13 | var theme = new FluentAvaloniaTheme
14 | {
15 | PreferSystemTheme = false,
16 | PreferUserAccentColor = false
17 | };
18 | builder.Instance.Styles.Add(theme);
19 | });
20 | }
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/CalculatorTests.Render#dark.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/IncludeThemeVariantTests/CalculatorTests.Render#dark.verified.png
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/CalculatorTests.Render#light.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/IncludeThemeVariantTests/CalculatorTests.Render#light.verified.png
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/CalculatorTests.Render.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MainWindow,
3 | SizeToContent: WidthAndHeight,
4 | Title: Simple Calculator,
5 | CanResize: false,
6 | Content: {
7 | Type: StackPanel,
8 | Spacing: 10.0,
9 | Width: 280.0,
10 | Height: 175.0,
11 | Margin: 10,
12 | HorizontalAlignment: Left,
13 | Children: [
14 | {
15 | Type: TextBox,
16 | Watermark: Operand 1,
17 | Name: FirstOperandInput
18 | },
19 | {
20 | Type: TextBox,
21 | Watermark: Operand 2,
22 | Name: SecondOperandInput
23 | },
24 | {
25 | Type: UniformGrid,
26 | Columns: 4,
27 | Children: [
28 | {
29 | Type: Button,
30 | Command: MainWindowViewModel.Add,
31 | Content: +,
32 | Name: AddButton
33 | },
34 | {
35 | Type: Button,
36 | Command: MainWindowViewModel.Subtract,
37 | Content: -,
38 | Name: SubtractButton
39 | },
40 | {
41 | Type: Button,
42 | Command: MainWindowViewModel.Multiply,
43 | Content: *,
44 | Name: MultiplyButton
45 | },
46 | {
47 | Type: Button,
48 | Command: MainWindowViewModel.Divide,
49 | Content: /,
50 | Name: DivideButton
51 | }
52 | ]
53 | },
54 | {
55 | Type: StackPanel,
56 | Spacing: 10.0,
57 | Orientation: Horizontal,
58 | Children: [
59 | {
60 | Type: TextBlock,
61 | Text: Result:
62 | },
63 | {
64 | Type: TextBlock,
65 | Name: ResultBox
66 | }
67 | ]
68 | }
69 | ]
70 | },
71 | Background: LightGray,
72 | Width: 300.0,
73 | Height: 195.0,
74 | IsVisible: true,
75 | DataContext: {
76 | AddCommand: MainWindowViewModel.Add,
77 | SubtractCommand: MainWindowViewModel.Subtract,
78 | MultiplyCommand: MainWindowViewModel.Multiply,
79 | DivideCommand: MainWindowViewModel.Divide
80 | }
81 | }
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/CalculatorTests.cs:
--------------------------------------------------------------------------------
1 | [TestFixture]
2 | public class CalculatorTests
3 | {
4 | [AvaloniaTest]
5 | public Task Render()
6 | {
7 | var window = new MainWindow
8 | {
9 | DataContext = new MainWindowViewModel()
10 | };
11 |
12 | return Verify(window);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using Avalonia;
2 | global using Avalonia.Headless;
3 | global using Avalonia.Headless.NUnit;
4 | global using TestableApp;
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/IncludeThemeVariantTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | TestAppBuilder.cs
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/IncludeThemeVariantTests/ModuleInit.cs:
--------------------------------------------------------------------------------
1 | public static class ModuleInit
2 | {
3 | #region EnableIncludeThemeVariant
4 |
5 | [ModuleInitializer]
6 | public static void Init()
7 | {
8 | VerifyAvalonia.IncludeThemeVariant();
9 | VerifierSettings.InitializePlugins();
10 | }
11 |
12 | #endregion
13 | }
--------------------------------------------------------------------------------
/src/NUnitTests/CalculatorTests.Should_Add_Numbers.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/NUnitTests/CalculatorTests.Should_Add_Numbers.verified.png
--------------------------------------------------------------------------------
/src/NUnitTests/CalculatorTests.Should_Add_Numbers.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MainWindow,
3 | SizeToContent: WidthAndHeight,
4 | Title: Simple Calculator,
5 | CanResize: false,
6 | Content: {
7 | Type: StackPanel,
8 | Spacing: 10.0,
9 | Width: 280.0,
10 | Height: 175.0,
11 | Margin: 10,
12 | HorizontalAlignment: Left,
13 | Children: [
14 | {
15 | Type: TextBox,
16 | Text: 10,
17 | Watermark: Operand 1,
18 | Name: FirstOperandInput
19 | },
20 | {
21 | Type: TextBox,
22 | Text: 20,
23 | Watermark: Operand 2,
24 | Name: SecondOperandInput
25 | },
26 | {
27 | Type: UniformGrid,
28 | Columns: 4,
29 | Children: [
30 | {
31 | Type: Button,
32 | Command: MainWindowViewModel.Add,
33 | Content: +,
34 | Name: AddButton
35 | },
36 | {
37 | Type: Button,
38 | Command: MainWindowViewModel.Subtract,
39 | Content: -,
40 | Name: SubtractButton
41 | },
42 | {
43 | Type: Button,
44 | Command: MainWindowViewModel.Multiply,
45 | Content: *,
46 | Name: MultiplyButton
47 | },
48 | {
49 | Type: Button,
50 | Command: MainWindowViewModel.Divide,
51 | Content: /,
52 | Name: DivideButton
53 | }
54 | ]
55 | },
56 | {
57 | Type: StackPanel,
58 | Spacing: 10.0,
59 | Orientation: Horizontal,
60 | Children: [
61 | {
62 | Type: TextBlock,
63 | Text: Result:
64 | },
65 | {
66 | Type: TextBlock,
67 | Text: 30,
68 | Name: ResultBox
69 | }
70 | ]
71 | }
72 | ]
73 | },
74 | Background: LightGray,
75 | Width: 300.0,
76 | Height: 195.0,
77 | IsVisible: true,
78 | DataContext: {
79 | FirstOperand: 10.0,
80 | SecondOperand: 20.0,
81 | Result: 30,
82 | AddCommand: MainWindowViewModel.Add,
83 | SubtractCommand: MainWindowViewModel.Subtract,
84 | MultiplyCommand: MainWindowViewModel.Multiply,
85 | DivideCommand: MainWindowViewModel.Divide
86 | }
87 | }
--------------------------------------------------------------------------------
/src/NUnitTests/CalculatorTests.cs:
--------------------------------------------------------------------------------
1 | [TestFixture]
2 | public class CalculatorTests
3 | {
4 | [AvaloniaTest]
5 | public Task Should_Add_Numbers()
6 | {
7 | var window = new MainWindow
8 | {
9 | DataContext = new MainWindowViewModel()
10 | };
11 |
12 | window.Show();
13 |
14 | // Set values to the input boxes
15 | window.FirstOperandInput.Text = "10";
16 | window.SecondOperandInput.Text = "20";
17 |
18 | // Raise click event on the button:
19 | window.AddButton.Focus();
20 | window.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None);
21 |
22 | Assert.That(window.ResultBox.Text, Is.EqualTo("30"));
23 | return Verify(window);
24 | }
25 | }
--------------------------------------------------------------------------------
/src/NUnitTests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using Avalonia;
2 | global using Avalonia.Headless;
3 | global using Avalonia.Headless.NUnit;
4 | global using Avalonia.Input;
5 | global using TestableApp;
6 |
--------------------------------------------------------------------------------
/src/NUnitTests/ModuleInit.cs:
--------------------------------------------------------------------------------
1 | public static class ModuleInit
2 | {
3 | #region Enable
4 |
5 | [ModuleInitializer]
6 | public static void Init()
7 | {
8 | VerifyImageMagick.RegisterComparers(0.17);
9 | VerifyAvalonia.Initialize();
10 | }
11 |
12 | #endregion
13 |
14 | [ModuleInitializer]
15 | public static void InitOther() =>
16 | VerifierSettings.InitializePlugins();
17 | }
--------------------------------------------------------------------------------
/src/NUnitTests/MyUserControlTests.Render.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/NUnitTests/MyUserControlTests.Render.verified.png
--------------------------------------------------------------------------------
/src/NUnitTests/MyUserControlTests.Render.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MyUserControl,
3 | Content: {
4 | Type: StackPanel,
5 | Spacing: 10.0,
6 | Orientation: Vertical,
7 | Margin: 10,
8 | HorizontalAlignment: Left,
9 | Children: [
10 | {
11 | Type: TextBlock,
12 | Text: Welcome to Avalonia!
13 | },
14 | {
15 | Type: Button,
16 | Content: Button
17 | }
18 | ]
19 | },
20 | Background: LightGray,
21 | Width: 200.0,
22 | Height: 100.0
23 | }
--------------------------------------------------------------------------------
/src/NUnitTests/MyUserControlTests.cs:
--------------------------------------------------------------------------------
1 | [TestFixture]
2 | public class MyUserControlTests
3 | {
4 | [AvaloniaTest]
5 | public Task Render()
6 | {
7 | var control = new MyUserControl();
8 | return Verify(control);
9 | }
10 | }
--------------------------------------------------------------------------------
/src/NUnitTests/NUnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/NUnitTests/TestAppBuilder.cs:
--------------------------------------------------------------------------------
1 | [assembly: AvaloniaTestApplication(typeof(TestAppBuilder))]
2 |
3 | public static class TestAppBuilder
4 | {
5 | public static AppBuilder BuildAvaloniaApp() =>
6 | AppBuilder.Configure()
7 | .UseSkia()
8 | .UseHeadless(
9 | new()
10 | {
11 | UseHeadlessDrawing = false
12 | });
13 | }
--------------------------------------------------------------------------------
/src/Shared.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | False
3 | Quiet
4 | True
5 | True
6 | True
7 | DO_NOT_SHOW
8 | ERROR
9 | ERROR
10 | ERROR
11 | WARNING
12 | ERROR
13 | ERROR
14 | ERROR
15 | ERROR
16 | ERROR
17 | ERROR
18 | ERROR
19 | ERROR
20 | ERROR
21 | ERROR
22 | ERROR
23 | ERROR
24 | ERROR
25 | ERROR
26 | ERROR
27 | ERROR
28 | ERROR
29 | ERROR
30 | ERROR
31 | ERROR
32 | ERROR
33 | ERROR
34 | ERROR
35 | ERROR
36 | ERROR
37 | ERROR
38 | ERROR
39 | ERROR
40 | ERROR
41 | ERROR
42 | ERROR
43 | DO_NOT_SHOW
44 | DO_NOT_SHOW
45 | ERROR
46 | ERROR
47 | ERROR
48 | ERROR
49 | ERROR
50 | ERROR
51 | ERROR
52 | ERROR
53 | ERROR
54 | ERROR
55 | ERROR
56 | ERROR
57 | C90+,E79+,S14+
58 | ERROR
59 | ERROR
60 | ERROR
61 | ERROR
62 | ERROR
63 | ERROR
64 | ERROR
65 | ERROR
66 | ERROR
67 | ERROR
68 | ERROR
69 | ERROR
70 | ERROR
71 | ERROR
72 | ERROR
73 | ERROR
74 | ERROR
75 | ERROR
76 | ERROR
77 | ERROR
78 | ERROR
79 | ERROR
80 | ERROR
81 | ERROR
82 | ERROR
83 | ERROR
84 | ERROR
85 | ERROR
86 | ERROR
87 | ERROR
88 | ERROR
89 | ERROR
90 | ERROR
91 | ERROR
92 | ERROR
93 | ERROR
94 | ERROR
95 | ERROR
96 | ERROR
97 | ERROR
98 | ERROR
99 | ERROR
100 | ERROR
101 | ERROR
102 | ERROR
103 | ERROR
104 | ERROR
105 | ERROR
106 | ERROR
107 | ERROR
108 | ERROR
109 | ERROR
110 | ERROR
111 | ERROR
112 | ERROR
113 | ERROR
114 | ERROR
115 | ERROR
116 | ERROR
117 | ERROR
118 | ERROR
119 | ERROR
120 | ERROR
121 | ERROR
122 | DO_NOT_SHOW
123 | *.received.*
124 | *.verified.*
125 | ERROR
126 | ERROR
127 | DO_NOT_SHOW
128 | ECMAScript 2016
129 | <?xml version="1.0" encoding="utf-16"?><Profile name="c# Cleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" /><CssAlphabetizeProperties>True</CssAlphabetizeProperties><JSStringLiteralQuotesDescriptor>True</JSStringLiteralQuotesDescriptor><CorrectVariableKindsDescriptor>True</CorrectVariableKindsDescriptor><VariablesToInnerScopesDescriptor>True</VariablesToInnerScopesDescriptor><StringToTemplatesDescriptor>True</StringToTemplatesDescriptor><JsInsertSemicolon>True</JsInsertSemicolon><RemoveRedundantQualifiersTs>True</RemoveRedundantQualifiersTs><OptimizeImportsTs>True</OptimizeImportsTs><OptimizeReferenceCommentsTs>True</OptimizeReferenceCommentsTs><PublicModifierStyleTs>True</PublicModifierStyleTs><ExplicitAnyTs>True</ExplicitAnyTs><TypeAnnotationStyleTs>True</TypeAnnotationStyleTs><RelativePathStyleTs>True</RelativePathStyleTs><AsInsteadOfCastTs>True</AsInsteadOfCastTs><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CssReformatCode>True</CssReformatCode><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><HtmlReformatCode>True</HtmlReformatCode><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><IDEA_SETTINGS><profile version="1.0">
130 | <option name="myName" value="c# Cleanup" />
131 | </profile></IDEA_SETTINGS><RIDER_SETTINGS><profile>
132 | <Language id="EditorConfig">
133 | <Reformat>false</Reformat>
134 | </Language>
135 | <Language id="HTML">
136 | <OptimizeImports>false</OptimizeImports>
137 | <Reformat>false</Reformat>
138 | <Rearrange>false</Rearrange>
139 | </Language>
140 | <Language id="JSON">
141 | <Reformat>false</Reformat>
142 | </Language>
143 | <Language id="RELAX-NG">
144 | <Reformat>false</Reformat>
145 | </Language>
146 | <Language id="XML">
147 | <OptimizeImports>false</OptimizeImports>
148 | <Reformat>false</Reformat>
149 | <Rearrange>false</Rearrange>
150 | </Language>
151 | </profile></RIDER_SETTINGS></Profile>
152 | ExpressionBody
153 | ExpressionBody
154 | ExpressionBody
155 | False
156 | NEVER
157 | NEVER
158 | False
159 | False
160 | False
161 | True
162 | False
163 | CHOP_ALWAYS
164 | False
165 | False
166 | RemoveIndent
167 | RemoveIndent
168 | False
169 | True
170 | True
171 | True
172 | True
173 | True
174 | ERROR
175 | DoNothing
176 |
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using System.Diagnostics.CodeAnalysis;
2 | global using Avalonia;
3 | global using Avalonia.Controls;
4 | global using Avalonia.Headless;
5 | global using Avalonia.Headless.XUnit;
6 | global using Avalonia.Themes.Fluent;
7 |
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/StandaloneExampleTest.XUnit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/Tests.Test.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/StandaloneExampleTest.XUnit/Tests.Test.verified.png
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/Tests.Test.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: Window,
3 | SizeToContent: WidthAndHeight,
4 | Content: {
5 | Type: Button,
6 | Content: Click me!,
7 | Width: 75.0,
8 | Height: 32.0
9 | },
10 | Width: 75.0,
11 | Height: 32.0,
12 | IsVisible: true
13 | }
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/Tests.cs:
--------------------------------------------------------------------------------
1 | [SuppressMessage("Performance", "CA1822:Mark members as static")]
2 | public class Tests
3 | {
4 | [AvaloniaFact]
5 | public Task Test()
6 | {
7 | var testSubject = new Button
8 | {
9 | Content = "Click me!",
10 | Width= 75,
11 | Height= 32
12 | };
13 |
14 | var window = new Window
15 | {
16 | Content = testSubject,
17 | SizeToContent = SizeToContent.WidthAndHeight,
18 | };
19 |
20 | return Verify(window);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/StandaloneExampleTest.XUnit/VerifyAvaloniaSetupApplication.cs:
--------------------------------------------------------------------------------
1 | [assembly: AvaloniaTestApplication(typeof(VerifyAvaloniaSetupApplication))]
2 |
3 | public class VerifyAvaloniaSetupApplication : Application
4 | {
5 | [ModuleInitializer]
6 | public static void Init()
7 | {
8 | VerifyImageMagick.RegisterComparers(.24);
9 | VerifierSettings.InitializePlugins();
10 | }
11 |
12 | public static AppBuilder BuildAvaloniaApp() =>
13 | AppBuilder
14 | .Configure()
15 | .UseSkia()
16 | .UseHeadless(
17 | new()
18 | {
19 | UseHeadlessDrawing = false
20 | });
21 |
22 | public VerifyAvaloniaSetupApplication() =>
23 | Styles.Add(new FluentTheme());
24 | }
--------------------------------------------------------------------------------
/src/TestableApp/App.axaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/TestableApp/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls.ApplicationLifetimes;
2 | using Avalonia.Data.Core.Plugins;
3 |
4 | // ReSharper disable PartialTypeWithSinglePart
5 |
6 | public partial class App : Application
7 | {
8 | public override void Initialize() =>
9 | AvaloniaXamlLoader.Load(this);
10 |
11 | public override void OnFrameworkInitializationCompleted()
12 | {
13 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
14 | {
15 | // Line below is needed to remove Avalonia data validation.
16 | // Without this line you will get duplicate validations from both Avalonia and CT
17 | BindingPlugins.DataValidators.RemoveAt(0);
18 | desktop.MainWindow = new MainWindow
19 | {
20 | DataContext = new MainWindowViewModel(),
21 | };
22 | }
23 |
24 | base.OnFrameworkInitializationCompleted();
25 | }
26 | }
--------------------------------------------------------------------------------
/src/TestableApp/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using Avalonia;
2 | global using Avalonia.Controls;
3 | global using Avalonia.Markup.Xaml;
4 | global using CommunityToolkit.Mvvm.ComponentModel;
5 | global using CommunityToolkit.Mvvm.Input;
6 | global using TestableApp;
--------------------------------------------------------------------------------
/src/TestableApp/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/TestableApp/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | namespace TestableApp;
2 |
3 | public partial class MainWindow : Window
4 | {
5 | public MainWindow() =>
6 | InitializeComponent();
7 | }
--------------------------------------------------------------------------------
/src/TestableApp/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | public partial class MainWindowViewModel : ObservableObject
2 | {
3 | [ObservableProperty]
4 | double? firstOperand;
5 |
6 | [ObservableProperty]
7 | double? secondOperand;
8 |
9 | [ObservableProperty]
10 | string? result;
11 |
12 | [RelayCommand]
13 | void Add() =>
14 | Result = (FirstOperand + SecondOperand)?.ToString();
15 |
16 | [RelayCommand]
17 | void Subtract() =>
18 | Result = (FirstOperand - SecondOperand)?.ToString();
19 |
20 | [RelayCommand]
21 | void Multiply() =>
22 | Result = (FirstOperand * SecondOperand)?.ToString();
23 |
24 | [RelayCommand]
25 | void Divide()
26 | {
27 | if (SecondOperand == 0)
28 | {
29 | Result = "Cannot divide by zero!";
30 | }
31 | else
32 | {
33 | Result = (FirstOperand / SecondOperand)?.ToString();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/TestableApp/MyUserControl.axaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/TestableApp/MyUserControl.axaml.cs:
--------------------------------------------------------------------------------
1 | namespace TestableApp;
2 |
3 | public partial class MyUserControl : UserControl
4 | {
5 | public MyUserControl() =>
6 | InitializeComponent();
7 | }
--------------------------------------------------------------------------------
/src/TestableApp/Program.cs:
--------------------------------------------------------------------------------
1 | static class Program
2 | {
3 | [STAThread]
4 | public static void Main(string[] args) =>
5 | AppBuilder.Configure()
6 | .UsePlatformDetect()
7 | .WithInterFont()
8 | .LogToTrace()
9 | .StartWithClassicDesktopLifetime(args);
10 | }
--------------------------------------------------------------------------------
/src/TestableApp/RecursiveWindow.axaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/TestableApp/RecursiveWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | namespace TestableApp;
2 |
3 | public partial class RecursiveWindow : Window
4 | {
5 | public RecursiveWindow()
6 | {
7 | InitializeComponent();
8 | DataContext = this;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/TestableApp/TestableApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net9.0
5 | true
6 | true
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/Verify.Avalonia.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29201.188
5 | MinimumVisualStudioVersion = 16.0.29201.188
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Verify.Avalonia", "Verify.Avalonia\Verify.Avalonia.csproj", "{C35E31DE-40A9-45C0-817B-41BE5B7D076E}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9A6C4741-C83D-4E05-A62F-8049F65B9B6C}"
9 | ProjectSection(SolutionItems) = preProject
10 | .editorconfig = .editorconfig
11 | .gitattributes = .gitattributes
12 | ..\.gitignore = ..\.gitignore
13 | appveyor.yml = appveyor.yml
14 | Directory.Build.props = Directory.Build.props
15 | Directory.Packages.props = Directory.Packages.props
16 | mdsnippets.json = mdsnippets.json
17 | ..\readme.md = ..\readme.md
18 | global.json = global.json
19 | EndProjectSection
20 | EndProject
21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestableApp", "TestableApp\TestableApp.csproj", "{F9113B4B-4BF1-4BB3-A124-AE71CC7364FF}"
22 | EndProject
23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NUnitTests", "NUnitTests\NUnitTests.csproj", "{AD731173-5BFC-4021-B834-AC391BBFDC40}"
24 | EndProject
25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XUnitTests", "XUnitTests\XUnitTests.csproj", "{F4EE4471-8E97-428E-A25F-09A838712461}"
26 | EndProject
27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{34E5995E-FC6C-449B-8FCA-EAE493025B81}"
28 | EndProject
29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StandaloneExampleTest.XUnit", "StandaloneExampleTest.XUnit\StandaloneExampleTest.XUnit.csproj", "{445C2DA8-74F4-4B6B-86FC-EC9D5AB87A9A}"
30 | EndProject
31 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IncludeThemeVariantTests", "IncludeThemeVariantTests\IncludeThemeVariantTests.csproj", "{ED0510B7-5FEF-43E7-9899-C55A5AE3A65B}"
32 | EndProject
33 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentAvaloniaTests", "FluentAvaloniaTests\FluentAvaloniaTests.csproj", "{FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74}"
34 | EndProject
35 | Global
36 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
37 | Debug|Any CPU = Debug|Any CPU
38 | Release|Any CPU = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
41 | {C35E31DE-40A9-45C0-817B-41BE5B7D076E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {C35E31DE-40A9-45C0-817B-41BE5B7D076E}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {C35E31DE-40A9-45C0-817B-41BE5B7D076E}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {C35E31DE-40A9-45C0-817B-41BE5B7D076E}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {F9113B4B-4BF1-4BB3-A124-AE71CC7364FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {F9113B4B-4BF1-4BB3-A124-AE71CC7364FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {F9113B4B-4BF1-4BB3-A124-AE71CC7364FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {F9113B4B-4BF1-4BB3-A124-AE71CC7364FF}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {AD731173-5BFC-4021-B834-AC391BBFDC40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {AD731173-5BFC-4021-B834-AC391BBFDC40}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {AD731173-5BFC-4021-B834-AC391BBFDC40}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {AD731173-5BFC-4021-B834-AC391BBFDC40}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {F4EE4471-8E97-428E-A25F-09A838712461}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 | {F4EE4471-8E97-428E-A25F-09A838712461}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 | {F4EE4471-8E97-428E-A25F-09A838712461}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {F4EE4471-8E97-428E-A25F-09A838712461}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {445C2DA8-74F4-4B6B-86FC-EC9D5AB87A9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {445C2DA8-74F4-4B6B-86FC-EC9D5AB87A9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {445C2DA8-74F4-4B6B-86FC-EC9D5AB87A9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {445C2DA8-74F4-4B6B-86FC-EC9D5AB87A9A}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {ED0510B7-5FEF-43E7-9899-C55A5AE3A65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {ED0510B7-5FEF-43E7-9899-C55A5AE3A65B}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {ED0510B7-5FEF-43E7-9899-C55A5AE3A65B}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {ED0510B7-5FEF-43E7-9899-C55A5AE3A65B}.Release|Any CPU.Build.0 = Release|Any CPU
65 | {FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74}.Release|Any CPU.Build.0 = Release|Any CPU
69 | EndGlobalSection
70 | GlobalSection(SolutionProperties) = preSolution
71 | HideSolutionNode = FALSE
72 | EndGlobalSection
73 | GlobalSection(ExtensibilityGlobals) = postSolution
74 | SolutionGuid = {B0B94980-5385-4EC6-A0EE-C9A191DDFC05}
75 | EndGlobalSection
76 | GlobalSection(NestedProjects) = preSolution
77 | {F4EE4471-8E97-428E-A25F-09A838712461} = {34E5995E-FC6C-449B-8FCA-EAE493025B81}
78 | {AD731173-5BFC-4021-B834-AC391BBFDC40} = {34E5995E-FC6C-449B-8FCA-EAE493025B81}
79 | {ED0510B7-5FEF-43E7-9899-C55A5AE3A65B} = {34E5995E-FC6C-449B-8FCA-EAE493025B81}
80 | {FCFD8D7C-A613-48D4-A09F-1D17FEDC7D74} = {34E5995E-FC6C-449B-8FCA-EAE493025B81}
81 | EndGlobalSection
82 | EndGlobal
83 |
--------------------------------------------------------------------------------
/src/Verify.Avalonia.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | ..\Shared.sln.DotSettings
3 | True
4 | True
5 | 1
6 | True
7 |
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Converters/AvaloniaConverter.cs:
--------------------------------------------------------------------------------
1 | class AvaloniaConverter :
2 | WriteOnlyJsonConverter
3 | where T : AvaloniaObject
4 | {
5 | static AvaloniaProperty[] properties =
6 | AvaloniaPropertyRegistry
7 | .Instance
8 | .GetRegistered(typeof(T))
9 | .Where(_ => !_.IsReadOnly)
10 | .ToArray();
11 |
12 | public override void Write(VerifyJsonWriter writer, T value)
13 | {
14 | writer.WriteStartObject();
15 | var typeHandling = writer.Serializer.TypeNameHandling;
16 | if (typeHandling != TypeNameHandling.All &&
17 | typeHandling != TypeNameHandling.Objects)
18 | {
19 | writer.WriteMember(value, value.GetType(), "Type");
20 | }
21 |
22 | foreach (var property in properties)
23 | {
24 | WriteMember(writer, value, property);
25 | }
26 |
27 | if (value is Panel panel)
28 | {
29 | writer.WriteMember(value, panel.Children, "Children");
30 | }
31 |
32 | writer.WriteEndObject();
33 | }
34 |
35 | static void WriteMember(VerifyJsonWriter writer, T parent, AvaloniaProperty property)
36 | {
37 | var diagnostic = parent.GetDiagnostic(property);
38 | if (diagnostic.Priority != BindingPriority.LocalValue)
39 | {
40 | return;
41 | }
42 |
43 | var value = diagnostic.Value;
44 | if (ReferenceEquals(value, parent))
45 | {
46 | return;
47 | }
48 |
49 | writer.WriteMember(parent, value, property.Name);
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Converters/CornerRadiusConverter.cs:
--------------------------------------------------------------------------------
1 | class CornerRadiusConverter :
2 | WriteOnlyJsonConverter
3 | {
4 | public override void Write(VerifyJsonWriter writer, CornerRadius value) =>
5 | writer.WriteValue(value.ToString());
6 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Converters/FontFamilyConverter.cs:
--------------------------------------------------------------------------------
1 | class FontFamilyConverter :
2 | WriteOnlyJsonConverter
3 | {
4 | public override void Write(VerifyJsonWriter writer, FontFamily value) =>
5 | writer.WriteValue(value.Name);
6 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Converters/ThicknessConverter.cs:
--------------------------------------------------------------------------------
1 | class ThicknessConverter :
2 | WriteOnlyJsonConverter
3 | {
4 | public override void Write(VerifyJsonWriter writer, Thickness value)
5 | {
6 | var top = value.Top;
7 | if (top == value.Left &&
8 | top == value.Right &&
9 | top == value.Bottom)
10 | {
11 | writer.WriteValue(top.ToString(CultureInfo.InvariantCulture));
12 | return;
13 | }
14 |
15 | writer.WriteValue(value.ToString());
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Extensions.cs:
--------------------------------------------------------------------------------
1 | static class Extensions
2 | {
3 | public static MemoryStream ToImage(this TopLevel topLevel)
4 | {
5 | using var bitmap = topLevel.CaptureRenderedFrame();
6 | if (bitmap == null)
7 | {
8 | throw new("No RenderedFrame");
9 | }
10 |
11 | var stream = new MemoryStream();
12 | bitmap.Save(stream);
13 | return stream;
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using System.Globalization;
2 | global using Argon;
3 | global using Avalonia;
4 | global using Avalonia.Controls;
5 | global using Avalonia.Data;
6 | global using Avalonia.Diagnostics;
7 | global using Avalonia.Headless;
8 | global using Avalonia.Input;
9 | global using Avalonia.Media;
--------------------------------------------------------------------------------
/src/Verify.Avalonia/Verify.Avalonia.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0;net9.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Verify.Avalonia/VerifyAvalonia.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Styling;
2 |
3 | namespace VerifyTests;
4 |
5 | public static partial class VerifyAvalonia
6 | {
7 | public static bool Initialized { get; private set; }
8 |
9 | public static void IncludeThemeVariant()
10 | {
11 | InnerVerifier.ThrowIfVerifyHasBeenRun();
12 | ShouldIncludeThemeVariant = true;
13 | }
14 |
15 | internal static bool ShouldIncludeThemeVariant;
16 |
17 | public static void Initialize()
18 | {
19 | if (Initialized)
20 | {
21 | throw new("Already Initialized");
22 | }
23 |
24 | Initialized = true;
25 |
26 | InnerVerifier.ThrowIfVerifyHasBeenRun();
27 | VerifierSettings.RegisterFileConverter(WindowToImage);
28 | VerifierSettings.RegisterFileConverter(TopLevelToImage);
29 | VerifierSettings.RegisterFileConverter(ControlToImage);
30 | AddConverters();
31 | }
32 |
33 | static ConversionResult ControlToImage(UserControl control, IReadOnlyDictionary context)
34 | {
35 | var window = new Window
36 | {
37 | Content = control,
38 | SizeToContent = SizeToContent.WidthAndHeight,
39 | };
40 | window.Show();
41 | return new(
42 | control,
43 | BuildWindowTargets(window),
44 | Cleanup(window));
45 | }
46 |
47 |
48 | static Func Cleanup(Window window) =>
49 | () =>
50 | {
51 | window.Close();
52 | return Task.CompletedTask;
53 | };
54 |
55 | static ConversionResult WindowToImage(Window window, IReadOnlyDictionary context)
56 | {
57 | window.Show();
58 | return new(
59 | window,
60 | BuildWindowTargets(window),
61 | Cleanup(window));
62 | }
63 |
64 | static IEnumerable BuildWindowTargets(TopLevel window)
65 | {
66 | if (ShouldIncludeThemeVariant)
67 | {
68 | var application = Application.Current!;
69 | application.RequestedThemeVariant = ThemeVariant.Light;
70 | var light = new Target("png", window.ToImage(), "light");
71 | application.RequestedThemeVariant = ThemeVariant.Dark;
72 | var dark = new Target("png", window.ToImage(), "dark");
73 | return [light, dark];
74 | }
75 |
76 | return [new("png", window.ToImage())];
77 | }
78 |
79 | static ConversionResult TopLevelToImage(TopLevel topLevel, IReadOnlyDictionary context) =>
80 | new(topLevel, BuildWindowTargets(topLevel));
81 | }
--------------------------------------------------------------------------------
/src/Verify.Avalonia/VerifyAvalonia_Converters.cs:
--------------------------------------------------------------------------------
1 | namespace VerifyTests;
2 |
3 | public static partial class VerifyAvalonia
4 | {
5 | static List avaloniaConverterAssemblies = [];
6 |
7 | static List converters =
8 | [
9 | new ThicknessConverter(),
10 | new CornerRadiusConverter(),
11 | new FontFamilyConverter()
12 | ];
13 |
14 | static VerifyAvalonia()
15 | {
16 | // Avalonia.Controls
17 | AddAvaloniaConvertersForAssemblyOfType();
18 | // Avalonia.Base
19 | AddAvaloniaConvertersForAssemblyOfType();
20 | // Avalonia.Controls.ColorPicker
21 | AddAvaloniaConvertersForAssemblyOfType();
22 | // Avalonia.Controls.DataGrid
23 | AddAvaloniaConvertersForAssemblyOfType();
24 | }
25 |
26 | ///
27 | /// Add instances for all types
28 | /// in the given assembly of the given type
29 | /// that are assignable to
30 | ///
31 | /// The type of the assembly to scan
32 | public static void AddAvaloniaConvertersForAssemblyOfType() =>
33 | AddAvaloniaConvertersForAssembly(typeof(T).Assembly);
34 |
35 | ///
36 | /// Add instances for all types
37 | /// in the given that are assignable to
38 | ///
39 | /// The assembly to scan
40 | public static void AddAvaloniaConvertersForAssembly(Assembly assembly)
41 | {
42 | InnerVerifier.ThrowIfVerifyHasBeenRun();
43 | avaloniaConverterAssemblies.Add(assembly);
44 | }
45 |
46 | static int GetDepth(Type type)
47 | {
48 | var level = 0;
49 | while (type != typeof(object))
50 | {
51 | level++;
52 | type = type.BaseType!;
53 | }
54 |
55 | return level;
56 | }
57 |
58 | static Type avaloniaConverterType = typeof(AvaloniaConverter<>);
59 | static Type avaloniaObjectType = typeof(AvaloniaObject);
60 |
61 | static void AddConverters()
62 | {
63 | var types = avaloniaConverterAssemblies
64 | .SelectMany(_ => _.GetTypes())
65 | .Where(_ =>
66 | _.IsAssignableTo(avaloniaObjectType) &&
67 | _ is
68 | {
69 | IsPublic: true,
70 | IsAbstract: false
71 | })
72 | .OrderByDescending(GetDepth);
73 | foreach (var type in types)
74 | {
75 | var genericType = avaloniaConverterType.MakeGenericType(type);
76 | converters.Add((WriteOnlyJsonConverter) Activator.CreateInstance(genericType)!);
77 | }
78 |
79 | VerifierSettings.AddExtraSettings(_ => _.Converters.AddRange(converters));
80 | }
81 | }
--------------------------------------------------------------------------------
/src/XUnitTests/CalculatorTests.Should_Add_Numbers.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/XUnitTests/CalculatorTests.Should_Add_Numbers.verified.png
--------------------------------------------------------------------------------
/src/XUnitTests/CalculatorTests.Should_Add_Numbers.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MainWindow,
3 | SizeToContent: WidthAndHeight,
4 | Title: Simple Calculator,
5 | CanResize: false,
6 | Content: {
7 | Type: StackPanel,
8 | Spacing: 10.0,
9 | Width: 280.0,
10 | Height: 175.0,
11 | Margin: 10,
12 | HorizontalAlignment: Left,
13 | Children: [
14 | {
15 | Type: TextBox,
16 | Text: 10,
17 | Watermark: Operand 1,
18 | Name: FirstOperandInput
19 | },
20 | {
21 | Type: TextBox,
22 | Text: 20,
23 | Watermark: Operand 2,
24 | Name: SecondOperandInput
25 | },
26 | {
27 | Type: UniformGrid,
28 | Columns: 4,
29 | Children: [
30 | {
31 | Type: Button,
32 | Command: MainWindowViewModel.Add,
33 | Content: +,
34 | Name: AddButton
35 | },
36 | {
37 | Type: Button,
38 | Command: MainWindowViewModel.Subtract,
39 | Content: -,
40 | Name: SubtractButton
41 | },
42 | {
43 | Type: Button,
44 | Command: MainWindowViewModel.Multiply,
45 | Content: *,
46 | Name: MultiplyButton
47 | },
48 | {
49 | Type: Button,
50 | Command: MainWindowViewModel.Divide,
51 | Content: /,
52 | Name: DivideButton
53 | }
54 | ]
55 | },
56 | {
57 | Type: StackPanel,
58 | Spacing: 10.0,
59 | Orientation: Horizontal,
60 | Children: [
61 | {
62 | Type: TextBlock,
63 | Text: Result:
64 | },
65 | {
66 | Type: TextBlock,
67 | Text: 30,
68 | Name: ResultBox
69 | }
70 | ]
71 | }
72 | ]
73 | },
74 | Background: LightGray,
75 | Width: 300.0,
76 | Height: 195.0,
77 | IsVisible: true,
78 | DataContext: {
79 | FirstOperand: 10.0,
80 | SecondOperand: 20.0,
81 | Result: 30,
82 | AddCommand: MainWindowViewModel.Add,
83 | SubtractCommand: MainWindowViewModel.Subtract,
84 | MultiplyCommand: MainWindowViewModel.Multiply,
85 | DivideCommand: MainWindowViewModel.Divide
86 | }
87 | }
--------------------------------------------------------------------------------
/src/XUnitTests/CalculatorTests.cs:
--------------------------------------------------------------------------------
1 | public class CalculatorTests
2 | {
3 | [AvaloniaFact]
4 | public Task Should_Add_Numbers()
5 | {
6 | var window = new MainWindow
7 | {
8 | DataContext = new MainWindowViewModel()
9 | };
10 |
11 | window.Show();
12 |
13 | // Set values to the input boxes
14 | window.FirstOperandInput.Text = "10";
15 | window.SecondOperandInput.Text = "20";
16 |
17 | // Raise click event on the button:
18 | window.AddButton.Focus();
19 | window.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None);
20 |
21 | Assert.Equal("30", window.ResultBox.Text);
22 | return Verify(window);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/XUnitTests/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using System.Diagnostics.CodeAnalysis;
2 | global using Avalonia;
3 | global using Avalonia.Headless;
4 | global using Avalonia.Headless.XUnit;
5 | global using Avalonia.Input;
6 | global using TestableApp;
--------------------------------------------------------------------------------
/src/XUnitTests/ModuleInit.cs:
--------------------------------------------------------------------------------
1 | public static class ModuleInit
2 | {
3 | [ModuleInitializer]
4 | public static void InitOther()
5 | {
6 | VerifyImageMagick.RegisterComparers(0.17);
7 | VerifierSettings.InitializePlugins();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/XUnitTests/MyUserControlTests.Render.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/XUnitTests/MyUserControlTests.Render.verified.png
--------------------------------------------------------------------------------
/src/XUnitTests/MyUserControlTests.Render.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: MyUserControl,
3 | Content: {
4 | Type: StackPanel,
5 | Spacing: 10.0,
6 | Orientation: Vertical,
7 | Margin: 10,
8 | HorizontalAlignment: Left,
9 | Children: [
10 | {
11 | Type: TextBlock,
12 | Text: Welcome to Avalonia!
13 | },
14 | {
15 | Type: Button,
16 | Content: Button
17 | }
18 | ]
19 | },
20 | Background: LightGray,
21 | Width: 200.0,
22 | Height: 100.0
23 | }
--------------------------------------------------------------------------------
/src/XUnitTests/MyUserControlTests.cs:
--------------------------------------------------------------------------------
1 | public class MyUserControlTests
2 | {
3 | [AvaloniaFact]
4 | public Task Render()
5 | {
6 | var control = new MyUserControl();
7 | return Verify(control);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/XUnitTests/TestAppBuilder.cs:
--------------------------------------------------------------------------------
1 | [assembly: AvaloniaTestApplication(typeof(TestAppBuilder))]
2 |
3 | public static class TestAppBuilder
4 | {
5 | public static AppBuilder BuildAvaloniaApp() =>
6 | AppBuilder.Configure()
7 | .UseSkia()
8 | .UseHeadless(
9 | new()
10 | {
11 | UseHeadlessDrawing = false
12 | });
13 | }
--------------------------------------------------------------------------------
/src/XUnitTests/Tests.Recursive.verified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/XUnitTests/Tests.Recursive.verified.png
--------------------------------------------------------------------------------
/src/XUnitTests/Tests.Recursive.verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | Type: RecursiveWindow,
3 | SizeToContent: WidthAndHeight,
4 | Title: RecursiveWindow,
5 | CanResize: false,
6 | Content: {
7 | Type: StackPanel,
8 | Spacing: 10.0,
9 | Margin: 10,
10 | HorizontalAlignment: Left
11 | },
12 | Background: LightGray,
13 | Width: 20.0,
14 | Height: 20.0,
15 | IsVisible: true
16 | }
--------------------------------------------------------------------------------
/src/XUnitTests/Tests.cs:
--------------------------------------------------------------------------------
1 | [SuppressMessage("Performance", "CA1822:Mark members as static")]
2 | public class Tests
3 | {
4 | [AvaloniaFact]
5 | public Task Recursive()
6 | {
7 | var window = new RecursiveWindow();
8 |
9 | return Verify(window);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/XUnitTests/XUnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/appveyor.yml:
--------------------------------------------------------------------------------
1 | image:
2 | - Visual Studio 2022
3 | # - macOS
4 | # - Ubuntu
5 | environment:
6 | DOTNET_NOLOGO: true
7 | DOTNET_CLI_TELEMETRY_OPTOUT: true
8 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
9 | before_build:
10 | - pwsh: |
11 | if ($isWindows) {
12 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./dotnet-install.ps1"
13 | ./dotnet-install.ps1 -JSonFile src/global.json -Architecture x64 -InstallDir 'C:\Program Files\dotnet'
14 | }
15 | if ($isMacOS) {
16 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh"
17 | sudo chmod u+x dotnet-install.sh
18 | sudo ./dotnet-install.sh --jsonfile src/global.json --architecture x64 --install-dir '/usr/local/share/dotnet'
19 | }
20 | if ($isLinux) {
21 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh"
22 | sudo chmod u+x dotnet-install.sh
23 | sudo ./dotnet-install.sh --jsonfile src/global.json --architecture x64 --install-dir '/usr/share/dotnet'
24 | }
25 | build_script:
26 | - dotnet build src --configuration Release
27 | - dotnet test src --configuration Release --no-build --no-restore
28 | test: off
29 | on_failure:
30 | - ps: Get-ChildItem *.received.* -recurse | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
31 | artifacts:
32 | - path: nugets\*.nupkg
--------------------------------------------------------------------------------
/src/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.300",
4 | "allowPrerelease": true,
5 | "rollForward": "latestFeature"
6 | }
7 | }
--------------------------------------------------------------------------------
/src/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/icon.png
--------------------------------------------------------------------------------
/src/key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VerifyTests/Verify.Avalonia/9fbf001484683f57e4ca0f5e03f8078b51251ede/src/key.snk
--------------------------------------------------------------------------------
/src/mdsnippets.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/master/schema.json",
3 | "TocExcludes": [ "NuGet package", "Release Notes", "Icon" ],
4 | "MaxWidth": 80,
5 | "ValidateContent": true,
6 | "Convention": "InPlaceOverwrite"
7 | }
--------------------------------------------------------------------------------
/src/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
20 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------