commit b3fa862f3907e402d9f37f4c4bd384a9b6cea9e6 Author: Sam Therapy Date: Sat May 13 20:10:14 2023 +0200 feat: Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml new file mode 100644 index 0000000..9e7c7a2 --- /dev/null +++ b/.github/workflows/build-test.yaml @@ -0,0 +1,60 @@ +name: Build + +on: [push, pull_request] + +jobs: + build: + strategy: + matrix: + operating-system: ["windows", "macos", "ubuntu"] + dotnet-version: ["7.0.x"] + + runs-on: ${{ matrix.operating-system }}-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.dotnet-version }} + - uses: actions/cache@v3 + with: + path: ~/.nuget/packages + # Look to see if there is a cache hit for the corresponding requirements file + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + restore-keys: | + ${{ runner.os }}-nuget + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build --configuration Release --no-restore + - name: Test + run: dotnet test --no-restore --verbosity normal + + publish: + needs: build + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup .NET Core SDK + uses: actions/setup-dotnet@v3 + - uses: actions/cache@v3 + with: + path: ~/.nuget/packages + # Look to see if there is a cache hit for the corresponding requirements file + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + restore-keys: | + ${{ runner.os }}-nuget + - name: Install dependencies + run: dotnet restore + - name: Build the package + run: dotnet build --configuration Release --no-restore -p:SymbolPackageFormat=symbols.nupkg + - name: Publish the package + run: dotnet nuget push src/Xdg.Directories/bin/Release/*.symbols.nupkg -s https://nuget.pkg.github.com/SamTherapy/index.json -k ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..d519025 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,68 @@ +# CodeQL Code Scanning +# Analyses your code for security vulnerabilities and coding errors. +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. You may wish to alter this file to override +# the set of languages analyzed, or to provide custom queries or build logic. +# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/about-code-scanning +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: "0 8 * * 4" + workflow_dispatch: + +jobs: + analyze: + name: Analyze + permissions: + actions: read + contents: read + security-events: write + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: ["csharp"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3.5.2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f17579 --- /dev/null +++ b/.gitignore @@ -0,0 +1,366 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Visual Studio Code files +.vscode/ + +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..66101a8 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,52 @@ +NETVERSION ?= net7.0 +PUBFLAGS ?= --framework $(NETVERSION) -c Release -p GeneratePackageOnBuild=false -p PublishAot=true -p AssemblyName=libxdg + +ifeq ($(OS),Windows_NT) + OSFLAG += win + ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) + := $(OSFLAG)-x64 + else + ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) + := $(OSFLAG)-x64 + endif + ifeq ($(PROCESSOR_ARCHITECTURE),x86) + := $(OSFLAG)-x86 + endif + endif +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + OSFLAG += linux + endif + ifeq ($(UNAME_S),Darwin) + OSFLAG += osx + endif + UNAME_M := $(shell uname -m) + ifeq ($(UNAME_M),x86_64) + OSFLAG := $(OSFLAG)-x64 + endif + ifeq ($(UNAME_M),x86) + OSFLAG := $(OSFLAG)-x86 + endif + ifeq ($(UNAME_M),arm64) + OSFLAG := $(OSFLAG)-arm64 + endif + ifeq ($(UNAME_M),arm) + OSFLAG := $(OSFLAG)-arm + endif +endif + +PUBFLAGS += -r $(OSFLAG) + +publish: src/Xdg.Directories/bin/Release/$(NETVERSION)/$(OSFLAG)/publish + +src/Xdg.Directories/bin/Release/$(NETVERSION)/$(OSFLAG)/publish: + dotnet publish ./src/Xdg.Directories $(PUBFLAGS) + +.PHONY: install +install: publish + make NETVERSION=$(NETVERSION) -C src/Xdg.Directories install + +.PHONY: uninstall +uninstall: + make -C src/Xdg.Directories uninstall \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5d45976 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Xdg.Net Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..737d3b9 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Xdg +---- +[![Build](https://github.com/SamTherapy/Xdg.Net/actions/workflows/build-test.yaml/badge.svg)](https://github.com/SamTherapy/Xdg.Net/actions/workflows/build-test.yaml) +[![CodeQL](https://github.com/SamTherapy/Xdg.Net/actions/workflows/codeql.yml/badge.svg)](https://github.com/SamTherapy/Xdg.Net/actions/workflows/codeql.yml) + +A .NET implementation of the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html). \ No newline at end of file diff --git a/Xdg.Net.sln b/Xdg.Net.sln new file mode 100644 index 0000000..9c84f7d --- /dev/null +++ b/Xdg.Net.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33627.172 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xdg.Directories", "src\Xdg.Directories\Xdg.Directories.csproj", "{D644CF8D-B8EB-4581-B075-9FD62BB5709A}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Xdg.Benchmarks", "src\Xdg.Benchmarks\Xdg.Benchmarks.fsproj", "{AEC4CC3D-E753-4D96-B8E8-B39B41EC0871}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xdg.Testing", "src\Xdg.Testing\Xdg.Testing.csproj", "{F5B4B166-F5F9-4D47-B426-CDA907C8B3E5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D644CF8D-B8EB-4581-B075-9FD62BB5709A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D644CF8D-B8EB-4581-B075-9FD62BB5709A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D644CF8D-B8EB-4581-B075-9FD62BB5709A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D644CF8D-B8EB-4581-B075-9FD62BB5709A}.Release|Any CPU.Build.0 = Release|Any CPU + {AEC4CC3D-E753-4D96-B8E8-B39B41EC0871}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEC4CC3D-E753-4D96-B8E8-B39B41EC0871}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEC4CC3D-E753-4D96-B8E8-B39B41EC0871}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEC4CC3D-E753-4D96-B8E8-B39B41EC0871}.Release|Any CPU.Build.0 = Release|Any CPU + {F5B4B166-F5F9-4D47-B426-CDA907C8B3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5B4B166-F5F9-4D47-B426-CDA907C8B3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5B4B166-F5F9-4D47-B426-CDA907C8B3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5B4B166-F5F9-4D47-B426-CDA907C8B3E5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6625754A-B79C-48B3-9B84-B7CF536AF30C} + EndGlobalSection +EndGlobal diff --git a/src/Xdg.Benchmarks/Program.fs b/src/Xdg.Benchmarks/Program.fs new file mode 100644 index 0000000..4489179 --- /dev/null +++ b/src/Xdg.Benchmarks/Program.fs @@ -0,0 +1,56 @@ +open BenchmarkDotNet.Attributes +open BenchmarkDotNet.Running +open BenchmarkDotNet.Jobs +open Xdg.Directories; + +[] +[] +//[] +[] +[] +type Benchmarks() = + // Base Directory + [] + member _.DataHome () = BaseDirectory.DataHome + [] + member _.ConfigHome () = BaseDirectory.ConfigHome + [] + member _.StateHome () = BaseDirectory.StateHome + [] + member _.BinHome () = BaseDirectory.BinHome + [] + member _.DataDirs () = BaseDirectory.DataDirs + [] + member _.ConfigDirs () = BaseDirectory.ConfigDirs + [] + member _.CacheHome () = BaseDirectory.CacheHome + [] + member _.RuntimeDir() = BaseDirectory.RuntimeDir + + // User Directories + [] + member _.DesktopDir () = UserDirectory.DesktopDir + [] + member _.DownloadDir () = UserDirectory.DownloadDir + [] + member _.DocumentsDir () = UserDirectory.DocumentsDir + [] + member _.MusicDir () = UserDirectory.MusicDir + [] + member _.PicturesDir () = UserDirectory.PicturesDir + [] + member _.VideosDir () = UserDirectory.VideosDir + [] + member _.TemplatesDir () = UserDirectory.TemplatesDir + [] + member _.PublicDir () = UserDirectory.PublicDir + + // Other + [] + member _.Home () = Other.Home + [] + member _.Applications () = Other.Applications + [] + member _.Fonts () = Other.Fonts + +BenchmarkRunner.Run() |> ignore \ No newline at end of file diff --git a/src/Xdg.Benchmarks/Xdg.Benchmarks.fsproj b/src/Xdg.Benchmarks/Xdg.Benchmarks.fsproj new file mode 100644 index 0000000..230b189 --- /dev/null +++ b/src/Xdg.Benchmarks/Xdg.Benchmarks.fsproj @@ -0,0 +1,43 @@ + + + + Exe + net7.0;net48 + false + false + True + True + True + True + latest-all + + + + 5 + + + + 5 + + + + 5 + + + + 5 + + + + + + + + + + + + + + + diff --git a/src/Xdg.Directories/BaseDirectory.cs b/src/Xdg.Directories/BaseDirectory.cs new file mode 100644 index 0000000..73731ed --- /dev/null +++ b/src/Xdg.Directories/BaseDirectory.cs @@ -0,0 +1,122 @@ +namespace Xdg.Directories; + +/// +public static class BaseDirectory +{ + /// + public static string DataHome + { + get => + Helpers.OS( + "XDG_DATA_HOME", + GetEnvironmentVariable("LOCALAPPDATA") + ?? GetFolderPath(SpecialFolder.LocalApplicationData), + $"{Other.Home}/Library/Application Support", + $"{Other.Home}/.local/share" + )!; + } + + /// + public static string ConfigHome + { + get => + Helpers.OS( + "XDG_CONFIG_HOME", + GetEnvironmentVariable("LOCALAPPDATA") + ?? GetFolderPath(SpecialFolder.LocalApplicationData), + $"{Other.Home}/Library/Application Support", + $"{Other.Home}/.config" + )!; + } + + /// + public static string StateHome + { + get => + Helpers.OS( + "XDG_STATE_HOME", + GetEnvironmentVariable("LOCALAPPDATA") + ?? GetFolderPath(SpecialFolder.LocalApplicationData), + $"{Other.Home}/Library/Application Support", + $"{Other.Home}/.local/state" + )!; + } + + /// + public static string? BinHome + { + get => Helpers.OS("XDG_BIN_HOME", null, null, $"{Other.Home}/.local/bin")!; + } + + /// + public static IList DataDirs + { + get => + Helpers.OS( + "XDG_DATA_DIRS", + new string[] + { + Helpers.AorB( + GetFolderPath(SpecialFolder.ApplicationData), + GetEnvironmentVariable("APPDATA")! + ), + GetEnvironmentVariable("PROGRAMDATA") + ?? GetFolderPath(SpecialFolder.CommonApplicationData) + }, + new string[] { "/Library/Application Support" }, + new string[] { "/usr/local/share", "/usr/share" } + )!; + } + + /// + public static IList ConfigDirs + { + get => + Helpers.OS( + "XDG_CONFIG_DIRS", + new string[] + { + GetEnvironmentVariable("PROGRAMDATA") + ?? GetFolderPath(SpecialFolder.CommonApplicationData), + Helpers.AorB( + GetFolderPath(SpecialFolder.ApplicationData), + GetEnvironmentVariable("APPDATA")! + ) + }, + new string[] + { + $"{Other.Home}/Library/Preferences", + "/Library/Application Support", + "/Library/Preferences" + }, + new string[] { "/etc/xdg" } + )!; + } + + /// + public static string CacheHome + { + get => + Helpers.OS( + "XDG_CACHE_HOME", + GetEnvironmentVariable("LOCALAPPDATA") is not null + ? $"{GetEnvironmentVariable("LOCALAPPDATA")}\\cache" + : $"{GetFolderPath(SpecialFolder.LocalApplicationData)}\\cache", + $"{Other.Home}/Library/Caches", + $"{Other.Home}/.cache" + )!; + } + + /// + public static string RuntimeDir + { + get => + Helpers.OS( + "XDG_RUNTIME_DIR", + GetEnvironmentVariable("LOCALAPPDATA") + ?? GetFolderPath(SpecialFolder.LocalApplicationData), + $"{Other.Home}/Library/Application Support", + $"/run/user/{GetEnvironmentVariable("UID")}" + )!; + } +} diff --git a/src/Xdg.Directories/FFI/BaseDirectory.cs b/src/Xdg.Directories/FFI/BaseDirectory.cs new file mode 100644 index 0000000..a89cfa7 --- /dev/null +++ b/src/Xdg.Directories/FFI/BaseDirectory.cs @@ -0,0 +1,90 @@ +#if NET7_0_OR_GREATER +#pragma warning disable CA1031 // General exceptions needed for handling errors +using System.Runtime.InteropServices; + +namespace Xdg.Directories.FFI; + +/// +/// Native library export wrappers +/// +internal static partial class Exports +{ + [UnmanagedCallersOnly(EntryPoint = "xdg_data_home")] + public static IntPtr DataHome() + { + try + { + return StringToPtr(BaseDirectory.DataHome); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_config_home")] + public static IntPtr ConfigHome() + { + try + { + return StringToPtr(BaseDirectory.ConfigHome); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_state_home")] + public static IntPtr StateHome() + { + try + { + return StringToPtr(BaseDirectory.StateHome); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_bin_home")] + public static IntPtr BinHome() + { + try + { + return StringToPtr(BaseDirectory.BinHome); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_cache_home")] + public static IntPtr CacheHome() + { + try + { + return StringToPtr(BaseDirectory.CacheHome); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_runtime_dir")] + public static IntPtr RuntimeDir() + { + try + { + return StringToPtr(BaseDirectory.RuntimeDir); + } + catch + { + return IntPtr.Zero; + } + } +} +#endif \ No newline at end of file diff --git a/src/Xdg.Directories/FFI/Helpers.cs b/src/Xdg.Directories/FFI/Helpers.cs new file mode 100644 index 0000000..3446867 --- /dev/null +++ b/src/Xdg.Directories/FFI/Helpers.cs @@ -0,0 +1,23 @@ +#if NET7_0_OR_GREATER +using System.Runtime.InteropServices; + +namespace Xdg.Directories.FFI; + +internal static partial class Exports +{ + /// + /// Frees the specified pointer + /// + /// + /// CALL THIS EVERY SINGLE TIME YOU USE SOMETHING FROM THIS LIBRARY!!!!!!
+ /// You will leak memory otherwise. + ///
+ /// The .NET Pointer to free + [UnmanagedCallersOnly(EntryPoint = "xdg_free")] + public static void Free(IntPtr p) + => Marshal.FreeCoTaskMem(p); + + internal static IntPtr StringToPtr(string? str) + => Marshal.StringToCoTaskMemUTF8(str); +} +#endif \ No newline at end of file diff --git a/src/Xdg.Directories/FFI/Other.cs b/src/Xdg.Directories/FFI/Other.cs new file mode 100644 index 0000000..c0c3ecf --- /dev/null +++ b/src/Xdg.Directories/FFI/Other.cs @@ -0,0 +1,21 @@ +#if NET7_0_OR_GREATER +#pragma warning disable CA1031 // General exceptions needed for handling errors +using System.Runtime.InteropServices; + +namespace Xdg.Directories.FFI; +internal static partial class Exports +{ + [UnmanagedCallersOnly(EntryPoint = "xdg_user_home")] + public static IntPtr UserHome() + { + try + { + return StringToPtr(Other.Home); + } + catch + { + return IntPtr.Zero; + } + } +} +#endif \ No newline at end of file diff --git a/src/Xdg.Directories/FFI/UserDirectory.cs b/src/Xdg.Directories/FFI/UserDirectory.cs new file mode 100644 index 0000000..37d9c8f --- /dev/null +++ b/src/Xdg.Directories/FFI/UserDirectory.cs @@ -0,0 +1,112 @@ +#if NET7_0_OR_GREATER +#pragma warning disable CA1031 // General exceptions needed for handling errors +using System.Runtime.InteropServices; + +namespace Xdg.Directories.FFI; +internal static partial class Exports +{ + [UnmanagedCallersOnly(EntryPoint = "xdg_desktop_dir")] + public static IntPtr Desktop() + { + try + { + return StringToPtr(UserDirectory.DesktopDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_download_dir")] + public static IntPtr Download() + { + try + { + return StringToPtr(UserDirectory.DownloadDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_documents_dir")] + public static IntPtr Documents() + { + try + { + return StringToPtr(UserDirectory.DocumentsDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_music_dir")] + public static IntPtr Music() + { + try + { + return StringToPtr(UserDirectory.MusicDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_pictures_dir")] + public static IntPtr Pictures() + { + try + { + return StringToPtr(UserDirectory.PicturesDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_videos_dir")] + public static IntPtr Videos() + { + try + { + return StringToPtr(UserDirectory.VideosDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_templates_dir")] + public static IntPtr Templates() + { + try + { + return StringToPtr(UserDirectory.TemplatesDir); + } + catch + { + return IntPtr.Zero; + } + } + + [UnmanagedCallersOnly(EntryPoint = "xdg_public_dir")] + public static IntPtr Public() + { + try + { + return StringToPtr(UserDirectory.PublicDir); + } + catch + { + return IntPtr.Zero; + } + } +} +#endif \ No newline at end of file diff --git a/src/Xdg.Directories/FFI/include/xdg.h b/src/Xdg.Directories/FFI/include/xdg.h new file mode 100644 index 0000000..4b42987 --- /dev/null +++ b/src/Xdg.Directories/FFI/include/xdg.h @@ -0,0 +1,57 @@ +#ifndef XDG_DOTNET_H +#define XDG_DOTNET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// XDG directory specifications API +// + +// Wrapper for XDG directories +typedef uintptr_t xdg_directory; + +// The current user's home directory +xdg_directory xdg_user_home(void); + +// Base directories + +xdg_directory xdg_data_home(void); + +xdg_directory xdg_config_home(void); + +xdg_directory xdg_state_home(void); + +xdg_directory xdg_bin_home(void); + +xdg_directory xdg_cache_home(void); + +xdg_directory xdg_runtime_dir(void); + +// User directories + +xdg_directory xdg_desktop_dir(void); + +xdg_directory xdg_download_dir(void); + +xdg_directory xdg_documents_dir(void); + +xdg_directory xdg_music_dir(void); + +xdg_directory xdg_pictures_dir(void); + +xdg_directory xdg_videos_dir(void); + +xdg_directory xdg_templates_dir(void); + +xdg_directory xdg_public_dir(void); + +// Frees the directory object. +void xdg_free(xdg_directory); + +#endif // !XDG_DOTNET_H +#ifdef __cplusplus +} +#endif diff --git a/src/Xdg.Directories/FFI/xdg.pc b/src/Xdg.Directories/FFI/xdg.pc new file mode 100644 index 0000000..bc96c56 --- /dev/null +++ b/src/Xdg.Directories/FFI/xdg.pc @@ -0,0 +1,10 @@ +prefix=/usr/local +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib + +Name: xdg +Description: xdg directory library +Version: 1.0.0 +Libs: -L${libdir} -lxdg +Cflags: -I${includedir} \ No newline at end of file diff --git a/src/Xdg.Directories/GNUmakefile b/src/Xdg.Directories/GNUmakefile new file mode 100644 index 0000000..7e46d2e --- /dev/null +++ b/src/Xdg.Directories/GNUmakefile @@ -0,0 +1,17 @@ +PREFIX ?= /usr/local +LIB ?= lib64 +BASE ?= bin/Release/$(NETVERSION)/linux-x64/publish + + +.PHONY: install +install: + sed -i 's|prefix=.*|prefix=$(PREFIX)|' $(BASE)/xdg.pc + install -Dm755 $(BASE)/libxdg.so $(PREFIX)/$(LIB) + install -Dm644 $(BASE)/xdg.pc $(PREFIX)/$(LIB)/pkgconfig + install -Dm644 $(BASE)/include/xdg.h $(PREFIX)/include + +.PHONY: uninstall +uninstall: + rm $(PREFIX)/$(LIB)/libxdg.so + rm $(PREFIX)/$(LIB)/pkgconfig/xdg.pc + rm $(PREFIX)/include/xdg.h \ No newline at end of file diff --git a/src/Xdg.Directories/Helpers.cs b/src/Xdg.Directories/Helpers.cs new file mode 100644 index 0000000..a485b85 --- /dev/null +++ b/src/Xdg.Directories/Helpers.cs @@ -0,0 +1,70 @@ +using System.Runtime.InteropServices; + +namespace Xdg.Directories; +static internal class Helpers +{ + /// + /// Return a specified value depending on the running operating system + /// + /// Environment variable to test initially + /// Windows directory + /// macOS Directory + /// Linux/BSD Directory + /// Env if set, otherwise variable depending on operating system + /// If running on another operating system + internal static string? OS(string Env, string? Windows, string? MacOS, string? Unix) + { + string? env = GetEnvironmentVariable(Env); + if (env is not null) + return env; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return Windows; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return MacOS; +#if NETSTANDARD + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +#elif NET + else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD()) +#endif + return Unix; + else + throw new NotSupportedException("Platforms not supported by .NET Standard are not supported."); + } + + /// + /// Return a specified value depending on the running operating system + /// + /// Environment variable to test initially + /// Windows directories + /// macOS Directories + /// Linux/BSD Directories + /// Env if set, otherwise variable depending on operating system + /// If running on another operating system + internal static IList? OS(string Env, IList? Windows, IList? MacOS, IList? Unix) + { + string? env = GetEnvironmentVariable(Env); + if (env is not null) + return env.Split(':')!; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return Windows; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return MacOS; +#if NETSTANDARD + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +#elif NET + else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD()) +#endif + return Unix; + else + throw new NotSupportedException("Platforms not supported by .NET Standard are not supported."); + } + + /// + /// Returns B if and only if A is empty. + /// + /// Value to test + /// Alternative if A is null or empty + /// B if A is null or empty, A if not + internal static string AorB(string A, string B) + => A is { Length: 0 } ? B : A; +} diff --git a/src/Xdg.Directories/Other.cs b/src/Xdg.Directories/Other.cs new file mode 100644 index 0000000..be335f1 --- /dev/null +++ b/src/Xdg.Directories/Other.cs @@ -0,0 +1,78 @@ +namespace Xdg.Directories; + +/// +public static class Other +{ + /// + public static string Home + { + get + { + // Unix ?? Windows + string? home = + GetEnvironmentVariable("HOME") + ?? GetEnvironmentVariable("USERPROFILE"); + if (home is not null) + return home; + else + return GetFolderPath(SpecialFolder.UserProfile); + } + } + + /// + public static IList Applications + { + get => + Helpers.OS( + "", + new string[] + { + GetFolderPath(SpecialFolder.Programs), + GetFolderPath(SpecialFolder.CommonPrograms) + }, + new string[] { "/Applications" }, + new string[] + { + $"{BaseDirectory.DataHome}/applications", + $"{Home}/.local/share/applications", + "/usr/local/share/applications", + "/usr/share/applications", + // TODO: Add $XDG_DATA_DIRS/applications + } + )!; + } + + /// + public static IList Fonts + { + get => + Helpers.OS( + "", + new string[] + { + GetEnvironmentVariable("SystemRoot") is not null + ? $"{GetEnvironmentVariable("SystemRoot")}\\Fonts" + : GetFolderPath(SpecialFolder.Fonts), + GetEnvironmentVariable("LOCALAPPDATA") is not null + ? $"{GetEnvironmentVariable("LOCALAPPDATA")}\\Microsoft\\Windows\\Fonts" + : $"{GetFolderPath(SpecialFolder.LocalApplicationData)}\\Microsoft\\Windows\\Fonts" + }, + new string[] + { + $"{Home}/Library/Fonts", + "/Library/Fonts", + "/System/Library/Fonts", + "/Network/Library/Fonts" + }, + new string[] + { + $"{BaseDirectory.DataHome}/fonts", + $"{Home}/.fonts", + $"{Home}/.local/share/fonts", + "/usr/local/share/fonts", + "/usr/share/fonts", + // TODO: Add $XDG_DATA_DIRS/fonts + } + )!; + } +} diff --git a/src/Xdg.Directories/UserDirectory.cs b/src/Xdg.Directories/UserDirectory.cs new file mode 100644 index 0000000..b052a5d --- /dev/null +++ b/src/Xdg.Directories/UserDirectory.cs @@ -0,0 +1,101 @@ +namespace Xdg.Directories; + +/// +public static class UserDirectory +{ + /// + public static string DesktopDir + { + get => + Helpers.OS( + "XDG_DESKTOP_DIR", + GetFolderPath(SpecialFolder.Desktop), + $"{Other.Home}/Desktop", + $"{Other.Home}/Desktop" + )!; + } + + /// + public static string? DownloadDir + { + get => + Helpers.OS( + "XDG_DOWNLOAD_DIR", + null, // TODO: Actually Implement? + $"{Other.Home}/Downloads", + $"{Other.Home}/Downloads" + )!; + } + + /// + public static string DocumentsDir + { + get => + Helpers.OS( + "XDG_DOCUMENTS_DIR", + GetFolderPath(SpecialFolder.MyDocuments), + $"{Other.Home}/Documents", + $"{Other.Home}/Documents" + )!; + } + + /// + public static string MusicDir + { + get => + Helpers.OS( + "XDG_MUSIC_DIR", + GetFolderPath(SpecialFolder.MyMusic), + $"{Other.Home}/Music", + $"{Other.Home}/Music" + )!; + } + + /// + public static string PicturesDir + { + get => + Helpers.OS( + "XDG_PICTURES_DIR", + GetFolderPath(SpecialFolder.MyPictures), + $"{Other.Home}/Pictures", + $"{Other.Home}/Pictures" + )!; + } + + /// + public static string VideosDir + { + get => + Helpers.OS( + "XDG_VIDEOS_DIR", + GetFolderPath(SpecialFolder.MyVideos), + $"{Other.Home}/Movies", + $"{Other.Home}/Videos" + )!; + } + + /// + public static string TemplatesDir + { + get => + Helpers.OS( + "XDG_TEMPLATES_DIR", + GetFolderPath(SpecialFolder.Templates), + $"{Other.Home}/Templates", + $"{Other.Home}/Templates" + )!; + } + + /// + public static string PublicDir + { + get => + Helpers.OS( + "XDG_PUBLICSHARE_DIR", + GetEnvironmentVariable("PUBLIC"), + $"{Other.Home}/Public", + $"{Other.Home}/Public" + )!; + } +} diff --git a/src/Xdg.Directories/Usings.cs b/src/Xdg.Directories/Usings.cs new file mode 100644 index 0000000..434d765 --- /dev/null +++ b/src/Xdg.Directories/Usings.cs @@ -0,0 +1 @@ +global using static System.Environment; \ No newline at end of file diff --git a/src/Xdg.Directories/Xdg.Directories.csproj b/src/Xdg.Directories/Xdg.Directories.csproj new file mode 100644 index 0000000..5c361bd --- /dev/null +++ b/src/Xdg.Directories/Xdg.Directories.csproj @@ -0,0 +1,110 @@ + + + true + + + + net7.0;netstandard2.0 + latest + true + true + enable + enable + True + latest-all + True + true + true + + + + Xdg.Directories.Net + .NET implementation of the XDG Base Directory Specification and user + directories + True + + True + README.md + LICENSE + True + snupkg + xdg;base-directories;base-directory;xdg-base-directory; + git + true + + preview.0 + + + + True + True + Link + + false + false + true + false + true + true + Size + + + + + + + 9999 + + + 9999 + + + 9999 + + + 9999 + + + + + True + \ + + + True + \ + + + + + + PreserveNewest + include\%(Filename)%(Extension) + + + + PreserveNewest + %(Filename)%(Extension) + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/src/Xdg.Directories/docs/BaseDirectory.xml b/src/Xdg.Directories/docs/BaseDirectory.xml new file mode 100644 index 0000000..1cd6a5a --- /dev/null +++ b/src/Xdg.Directories/docs/BaseDirectory.xml @@ -0,0 +1,315 @@ + + + + + The XDG Base Directory specification is a standard created by freedesktop.org that standardizes the location of storing application files. + + + +
+ This allows users to have less clutter in their home directories, and allows programmers to not have to hard-code directories. +
+ All operating systems that are supported by .NET (Windows, macOS, Linux, FreeBSD at the time of writing) are supported. +
+ For all base directory files, the directories are resolved as follows: + + + + The respective XDG_* enivronment variable + + will always be used if specified + + + + Operating systemd dependent fallback: + + Windows + + Use Known Folders. + + + + macOS + + Follow the Apple documentation on application-specific files. + + + + Linux/FreeBSD + + Follow the XDG Base Directory specification. + + + + + +
+
+ + + Base directory for data files. + + + A single base directory relative to which user-specifc data files should be written. + + + If XDG_DATA_HOME is set, the directory specified. + + Else, + + Windows + + %LOCALAPPDATA% + + + + macOS + + $HOME/Library/Application Support + + + + Linux/FreeBSD + + $HOME/.local/share + + + + + + + + Base directory for configuration files. + + + A single base directory relative to which user-specifc configuration files should be written. + + + If XDG_CONFIG_HOME is set, the directory specified. + + Else, + + Windows + + %LOCALAPPDATA% + + + + macOS + + $HOME/Library/Application Support + + + + Linux/FreeBSD + + $HOME/.config + + + + + + + + Base directory for state data. + + + A single base directory relative to which user-specifc state data should be written. + + + If XDG_STATE_HOME is set, the directory specified. + + Else, + + Windows + + %LOCALAPPDATA% + + + + macOS + + $HOME/Library/Application Support + + + + Linux/FreeBSD + + $HOME/.local/state + + + + + + + + Base directory for executable files. + + + A single base directory relative to which user-specifc executable files should be written. + + + If XDG_BIN_HOME is set, the directory specified. + + Else, + + Windows + + null +
+ Windows does not support this by default. +
+
+ + macOS + + null +
+ macOS does not support this by default. +
+
+ + Linux/FreeBSD + + $HOME/.local/bin + + +
+ NOTE: This is not an XDG standard but a de facto standard. +
+
+ + + A list of directories to search for data files. + + + A set of preference-ordered base directories to which data files should be searched. + + + If XDG_DATA_DIRS is set, a list of the directories specified. + + Else, + + Windows + + %APPADATA%, + %ProgramData% + + + + macOS + + /Library/Application Support + + + + Linux/FreeBSD + + /usr/local/share/, + /usr/share/ + + + + + + + + A list of directories to look for configuration files. + + + A set of preference-ordered base directories to which configuration files should be searched. + + + If XDG_CONFIG_DIRS is set, a list of the directories specified. + + Else, + + Windows + + %ProgramData%, + %APPADATA% + + + + macOS + + ~/Library/Preferences, + /Library/Application Support, + /Library/Preferences + + + + Linux/FreeBSD + + /etc/xdg + + + + This is typically not used, for most use cases ConfigHome should be used instead. + + + + + Base directory for non-essential data. + + + A single base directory relative to which user-specifc non-essential data should be written. + + + If XDG_CACHE_HOME is set, the directory specified. + + Else, + + Windows + + %LOCALAPPDATA%\cache + + + + macOS + + $HOME/Library/Caches + + + + Linux/FreeBSD + + $HOME/.cache + + + + + + + + Base directory for runtime-specific files. + + + A single base directory relative to which user-specifc runtime files should be written. + + + If XDG_RUNTIME_DIR is set, the directory specified. + + Else, + + Windows + + %LOCALAPPDATA% + + + + macOS + + $HOME/Library/Application Support + + + + Linux/FreeBSD + + /run/user/$UID + + + + + +
\ No newline at end of file diff --git a/src/Xdg.Directories/docs/Other.xml b/src/Xdg.Directories/docs/Other.xml new file mode 100644 index 0000000..b0d240f --- /dev/null +++ b/src/Xdg.Directories/docs/Other.xml @@ -0,0 +1,104 @@ + + + + + Other useful directories that aren't specified by XDG. + + + + + Home Directory + + + The current user's home directory. + + + + + Windows + + %USERPROFILE% + + + + Unix (macOS/Linux/FreeBSD) + + $HOME + + + + + + + + Application directories + + + Common application directories. + + + + + Windows + + The Programs Special Folder, + the Common Programs Special Folder + + + + macOS + + /Applications + + + + Linux/FreeBSD + + $XDG_DATA_HOME/applications, + $HOME/.local/share/applications, + /usr/local/share/applications, + /usr/share/applications + + + + + + + + Font directories + + + Common font directories. + + + + + Windows + + %SYSTEMROOT%\Fonts, + %LOCALAPPDATA%\Microsoft\Windows\Fonts + + + + macOS + + $HOME/Library/Fonts, + /Library/Fonts, + /System/Library/Fonts, + /Network/Library/Fonts + + + + Linux/FreeBSD + + $XDG_DATA_HOME/fonts, + $HOME/.fonts, + $HOME/.local/share/fonts, + /usr/local/share/fonts + /usr/share/fonts + + + + + + \ No newline at end of file diff --git a/src/Xdg.Directories/docs/UserDirectory.xml b/src/Xdg.Directories/docs/UserDirectory.xml new file mode 100644 index 0000000..9e30412 --- /dev/null +++ b/src/Xdg.Directories/docs/UserDirectory.xml @@ -0,0 +1,266 @@ + + + + + Well-known user directories like desktop, documents and music folders. + + + + + Desktop folder + + + The user's desktop directory. + + + If XDG_DESKTOP_DIR is set, the directory specified. + + Else, + + Windows + + The Desktop Special Folder + + + + macOS + + $HOME/Desktop + + + + Linux/FreeBSD + + $HOME/Desktop + + + + + + + + Download folder + + + A location to store downloaded files. + + + If XDG_DOWNLOAD_DIR is set, the directory specified. + + Else, + + Windows + + null +
+ Windows does not specify the Downloads folder in its magic folder list. +
+
+ + macOS + + $HOME/Downloads + + + + Linux/FreeBSD + + $HOME/Downloads + + +
+
+
+ + + Document folder + + + A location to store documents files. + + + If XDG_DOCUMENTS_DIR is set, the directory specified. + + Else, + + Windows + + The Documents Special Folder + + + + macOS + + $HOME/Documents + + + + Linux/FreeBSD + + $HOME/Documents + + + + + + + + Music folder + + + A location to store music files. + + + If XDG_MUSIC_DIR is set, the directory specified. + + Else, + + Windows + + The Music Special Folder + + + + macOS + + $HOME/Music + + + + Linux/FreeBSD + + $HOME/Music + + + + + + + + Image folder + + + A location to store image files. + + + If XDG_PICTURES_DIR is set, the directory specified. + + Else, + + Windows + + The Pictures Special Folder + + + + macOS + + $HOME/Pictures + + + + Linux/FreeBSD + + $HOME/Pictures + + + + + + + + Video folder + + + A location to store video files. + + + If XDG_VIDEOS_DIR is set, the directory specified. + + Else, + + Windows + + The Videos Special Folder + + + + macOS + + $HOME/Movies + + + + Linux/FreeBSD + + $HOME/Videos + + + + + + + + Template folder + + + A location to store template files. + + + If XDG_TEMPLATES_DIR is set, the directory specified. + + Else, + + Windows + + The Templates Special Folder + + + + macOS + + $HOME/Templates + + + + Linux/FreeBSD + + $HOME/Templatess + + + + + + + + Public folder + + + A location to store public / shared files. + + + If XDG_PUBLICSHARE_DIR is set, the directory specified. + + Else, + + Windows + + %PUBLIC% + + + + macOS + + $HOME/Public + + + + Linux/FreeBSD + + $HOME/Public + + + + + +
diff --git a/src/Xdg.Directories/packages.lock.json b/src/Xdg.Directories/packages.lock.json new file mode 100644 index 0000000..6b9081d --- /dev/null +++ b/src/Xdg.Directories/packages.lock.json @@ -0,0 +1,95 @@ +{ + "version": 1, + "dependencies": { + ".NETStandard,Version=v2.0": { + "Microsoft.SourceLink.Gitea": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "x8BtF0TXPPhN1ujosXGJQHiXcBi/ppH/dmzeQhOsgmYlCuKqUjde1KpWZl7CK/2BjM6yEkH5ZPf0DCjC0DRnVQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "MinVer": { + "type": "Direct", + "requested": "[4.3.0, )", + "resolved": "4.3.0", + "contentHash": "YNVAW3loCFW4kTwensApaZUl+7xREK75QQNOFSbsbXx2sCSm9/IHBjUHsJGn3u0UA5r/sAqrdYBNUlOFfLhUrA==" + }, + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" + } + }, + "net7.0": { + "Microsoft.SourceLink.Gitea": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "x8BtF0TXPPhN1ujosXGJQHiXcBi/ppH/dmzeQhOsgmYlCuKqUjde1KpWZl7CK/2BjM6yEkH5ZPf0DCjC0DRnVQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "MinVer": { + "type": "Direct", + "requested": "[4.3.0, )", + "resolved": "4.3.0", + "contentHash": "YNVAW3loCFW4kTwensApaZUl+7xREK75QQNOFSbsbXx2sCSm9/IHBjUHsJGn3u0UA5r/sAqrdYBNUlOFfLhUrA==" + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" + } + } + } +} \ No newline at end of file diff --git a/src/Xdg.Testing/Directories/BaseDirectory_test.cs b/src/Xdg.Testing/Directories/BaseDirectory_test.cs new file mode 100644 index 0000000..6b5ec70 --- /dev/null +++ b/src/Xdg.Testing/Directories/BaseDirectory_test.cs @@ -0,0 +1,269 @@ +namespace Xdg.Directories.Testing.Directories; + +[TestClass] +public class BaseDirectory_Test +{ + [TestClass, TestCategory("Windows")] + public class Windows + { + [TestMethod, TestCategory("DataHome")] + public void DataHome_Windows_Default() + { + Helper.Prepare("XDG_DATA_HOME", null, "Windows"); + Assert.AreEqual(BaseDirectory.DataHome, GetFolderPath(SpecialFolder.LocalApplicationData)); + } + + [TestMethod, TestCategory("ConfigHome")] + public void ConfigHome_Windows_Default() + { + Helper.Prepare("XDG_CONFIG_HOME", null, "Windows"); + Assert.AreEqual(BaseDirectory.ConfigHome, GetFolderPath(SpecialFolder.LocalApplicationData)); + } + + [TestMethod, TestCategory("StateHome")] + public void StateHome_Windows_Default() + { + Helper.Prepare("XDG_STATE_HOME", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.LocalApplicationData), BaseDirectory.StateHome); + } + + [TestMethod, TestCategory("BinHome")] + public void BinHome_Windows_Default() + { + Helper.Prepare("XDG_BIN_HOME", null, "Windows"); + Assert.IsNull(BaseDirectory.BinHome); + } + + [TestMethod, TestCategory("CacheHome")] + public void CacheHome_Windows_Default() + { + Helper.Prepare("XDG_CACHE_HOME", null, "Windows"); + Assert.AreEqual($"{GetFolderPath(SpecialFolder.LocalApplicationData)}\\cache", BaseDirectory.CacheHome); + } + + [TestMethod, TestCategory("RuntimeDir")] + public void RuntimeDir_Windows_Default() + { + Helper.Prepare("XDG_RUNTIME_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.LocalApplicationData), BaseDirectory.RuntimeDir); + } + + [TestMethod, TestCategory("DataDirs")] + public void DataDirs_Windows_Default() + { + Helper.Prepare("XDG_DATA_DIRS", null, "Windows"); + CollectionAssert.AreEqual( + new string[] { GetEnvironmentVariable("APPDATA")!, GetEnvironmentVariable("PROGRAMDATA")! }, + (System.Collections.ICollection)BaseDirectory.DataDirs + ); + } + + [TestMethod, TestCategory("ConfigDirs")] + public void ConfigDirs_Windows_Default() + { + Helper.Prepare("XDG_CONFIG_DIRS", null, "Windows"); + CollectionAssert.AreEqual( + new string[] { GetEnvironmentVariable("PROGRAMDATA")!, GetEnvironmentVariable("APPDATA")! }, + (System.Collections.ICollection)BaseDirectory.ConfigDirs + ); + } + } + + [TestClass, TestCategory("MacOS")] + public class MacOS + { + [TestMethod, TestCategory("DataHome")] + public void DataHome_MacOS_Default() + { + Helper.Prepare("XDG_DATA_HOME", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Library/Application Support", BaseDirectory.DataHome); + } + + [TestMethod, TestCategory("ConfigHome")] + public void ConfigHome_MacOS_Default() + { + Helper.Prepare("XDG_CONFIG_HOME", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Library/Application Support", BaseDirectory.ConfigHome); + } + + [TestMethod, TestCategory("StateHome")] + public void StateHome_MacOS_Default() + { + Helper.Prepare("XDG_STATE_HOME", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Library/Application Support", BaseDirectory.StateHome); + } + + [TestMethod, TestCategory("BinHome")] + public void BinHome_MacOS_Default() + { + Helper.Prepare("XDG_BIN_HOME", null, "MacOS"); + Assert.IsNull(BaseDirectory.BinHome); + } + + [TestMethod, TestCategory("CacheHome")] + public void CacheHome_MacOS_Default() + { + Helper.Prepare("XDG_CACHE_HOME", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Library/Caches", BaseDirectory.CacheHome); + } + + [TestMethod, TestCategory("RuntimeDir")] + public void RuntimeDir_MacOS_Default() + { + Helper.Prepare("XDG_RUNTIME_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Library/Application Support", BaseDirectory.RuntimeDir); + } + + [TestMethod, TestCategory("DataDirs")] + public void DataDirs_MacOS_Default() + { + Helper.Prepare("XDG_DATA_DIRS", null, "MacOS"); + CollectionAssert.AreEqual( + new string[] { "/Library/Application Support" }, + (System.Collections.ICollection)BaseDirectory.DataDirs + ); + } + + [TestMethod, TestCategory("ConfigDirs")] + public void ConfigDirs_MacOS_Default() + { + Helper.Prepare("XDG_CONFIG_DIRS", null, "MacOS"); + CollectionAssert.AreEqual( + new string[] { $"{Other.Home}/Library/Preferences", "/Library/Application Support", "/Library/Preferences" }, + (System.Collections.ICollection)BaseDirectory.ConfigDirs + ); + } + } + + [TestClass, TestCategory("Linux")] + public class Linux + { + [TestMethod, TestCategory("DataHome")] + public void DataHome_Linux_Default() + { + Helper.Prepare("XDG_DATA_HOME", null, "Linux"); + Assert.AreEqual($"{Other.Home}/.local/share", BaseDirectory.DataHome); + } + + [TestMethod, TestCategory("ConfigHome")] + public void ConfigHome_Linux_Default() + { + Helper.Prepare("XDG_CONFIG_HOME", null, "Linux"); + Assert.AreEqual($"{Other.Home}/.config", BaseDirectory.ConfigHome); + } + + [TestMethod, TestCategory("StateHome")] + public void StateHome_Linux_Default() + { + Helper.Prepare("XDG_STATE_HOME", null, "Linux"); + Assert.AreEqual($"{Other.Home}/.local/state", BaseDirectory.StateHome); + } + + [TestMethod, TestCategory("BinHome")] + public void BinHome_Linux_Default() + { + Helper.Prepare("XDG_BIN_HOME", null, "Linux"); + Assert.AreEqual($"{Other.Home}/.local/bin", BaseDirectory.BinHome); + } + + [TestMethod, TestCategory("CacheHome")] + public void CacheHome_Linux_Default() + { + Helper.Prepare("XDG_CACHE_HOME", null, "Linux"); + Assert.AreEqual($"{Other.Home}/.cache", BaseDirectory.CacheHome); + } + + [TestMethod, TestCategory("RuntimeDir")] + public void RuntimeDir_Linux_Default() + { + Helper.Prepare("XDG_RUNTIME_DIR", null, "Linux"); + Assert.AreEqual($"/run/user/{GetEnvironmentVariable("UID")}", BaseDirectory.RuntimeDir); + } + + [TestMethod, TestCategory("DataDirs")] + public void DataDirs_Linux_Default() + { + Helper.Prepare("XDG_DATA_DIRS", null, "Linux"); + CollectionAssert.AreEqual( + new string[] { "/usr/local/share", "/usr/share" }, + (System.Collections.ICollection)BaseDirectory.DataDirs + ); + } + + [TestMethod, TestCategory("ConfigDirs")] + public void ConfigDirs_Linux_Default() + { + Helper.Prepare("XDG_CONFIG_DIRS", null, "Linux"); + CollectionAssert.AreEqual( + new string[] { "/etc/xdg" }, + (System.Collections.ICollection)BaseDirectory.ConfigDirs + ); + } + } + + [TestClass, TestCategory("SetEnv")] + public class Env + { + [TestMethod, TestCategory("DataHome")] + public void DataHome_SetEnv() + { + SetEnvironmentVariable("XDG_DATA_HOME", "/"); + Assert.AreEqual("/", BaseDirectory.DataHome); + } + + [TestMethod, TestCategory("ConfigHome")] + public void ConfigHome_SetEnv() + { + SetEnvironmentVariable("XDG_CONFIG_HOME", "/"); + Assert.AreEqual("/", BaseDirectory.ConfigHome); + } + + [TestMethod, TestCategory("StateHome")] + public void StateHome_SetEnv() + { + SetEnvironmentVariable("XDG_STATE_HOME", "/"); + Assert.AreEqual("/", BaseDirectory.StateHome); + } + + [TestMethod, TestCategory("BinHome")] + public void BinHome_SetEnv() + { + SetEnvironmentVariable("XDG_BIN_HOME", "/"); + Assert.AreEqual("/", BaseDirectory.BinHome); + } + + [TestMethod, TestCategory("CacheHome")] + public void CacheHome_SetEnv() + { + SetEnvironmentVariable("XDG_CACHE_HOME", "/"); + Assert.AreEqual("/", BaseDirectory.CacheHome); + } + + [TestMethod, TestCategory("RuntimeDir")] + public void RuntimeDir_SetEnv() + { + SetEnvironmentVariable("XDG_RUNTIME_DIR", "/"); + Assert.AreEqual("/", BaseDirectory.RuntimeDir); + } + + [TestMethod, TestCategory("DataDirs")] + public void DataDirs_SetEnv() + { + SetEnvironmentVariable("XDG_DATA_DIRS", "/:/"); + CollectionAssert.AreEqual( + new string[] { "/", "/" }, + (System.Collections.ICollection)BaseDirectory.DataDirs + ); + } + + [TestMethod, TestCategory("DataDirs")] + public void ConfigDirs_SetEnv() + { + SetEnvironmentVariable("XDG_CONFIG_DIRS", "/:/:/"); + CollectionAssert.AreEqual( + new string[] { "/", "/", "/" }, + (System.Collections.ICollection)BaseDirectory.ConfigDirs + ); + } + } +} \ No newline at end of file diff --git a/src/Xdg.Testing/Directories/HelperMethods.cs b/src/Xdg.Testing/Directories/HelperMethods.cs new file mode 100644 index 0000000..fcd8c34 --- /dev/null +++ b/src/Xdg.Testing/Directories/HelperMethods.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; + +namespace Xdg.Directories.Testing.Directories; +internal static class Helper +{ + public static void Prepare(string Env, string? EnvValue, string OS) + { + OSCheck(OS); + SetEnvironmentVariable(Env, EnvValue); + } + + public static void OSCheck(string os) + { + switch (os.ToLower()) + { + case "windows": + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + Assert.Inconclusive("Not running on Windows"); + break; + case "macos": + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + Assert.Inconclusive("Not running on macOS"); + break; + case "linux": + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + Assert.Inconclusive("Not running on Linux"); + break; +#if NET + case "freebsd": + if (!OperatingSystem.IsFreeBSD()) + Assert.Inconclusive("Not running on FreeBSD"); + break; +#endif + default: + Assert.Fail("Not supported"); + break; + } + } +} diff --git a/src/Xdg.Testing/Directories/Other_test.cs b/src/Xdg.Testing/Directories/Other_test.cs new file mode 100644 index 0000000..6fcc752 --- /dev/null +++ b/src/Xdg.Testing/Directories/Other_test.cs @@ -0,0 +1,101 @@ +namespace Xdg.Directories.Testing.Directories; + +[TestClass] +public class Other_Test +{ + [TestClass, TestCategory("Windows")] + public class Windows + { + [TestMethod, TestCategory("Home")] + public void Home_Windows_Default() + { + Helper.Prepare("DISCARD", null, "Windows"); + Assert.AreEqual(GetEnvironmentVariable("USERPROFILE"), Other.Home); + } + + [TestMethod, TestCategory("Home")] + public void Home_Windows_NoUserProfile() + { + Helper.Prepare("USERPROFILE", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.UserProfile), Other.Home); + } + + [TestMethod, TestCategory("Applications")] + public void Applications_Windows_Default() + { + Helper.Prepare("DISCARD", null, "Windows"); + CollectionAssert.AreEquivalent(new string[] { GetFolderPath(SpecialFolder.Programs), GetFolderPath(SpecialFolder.CommonPrograms) }, (System.Collections.ICollection)Other.Applications); + } + + [TestMethod, TestCategory("Fonts")] + public void Fonts_Windows_Default() + { + Helper.Prepare("DISCARD", null, "Windows"); + CollectionAssert.AreEquivalent(new string[] { GetFolderPath(SpecialFolder.Fonts), $"{GetFolderPath(SpecialFolder.LocalApplicationData)}\\Microsoft\\Windows\\Fonts" }, (System.Collections.ICollection)Other.Fonts); + } + } + + [TestClass, TestCategory("MacOS")] + public class MacOS + { + [TestMethod, TestCategory("Home")] + public void Home_MacOS_Default() + { + Helper.Prepare("DISCARD", null, "macOS"); + Assert.AreEqual(GetEnvironmentVariable("HOME"), Other.Home); + } + + [TestMethod, TestCategory("Home")] + public void Home_MacOS_NoHome() + { + Helper.Prepare("HOME", null, "macOS"); + Assert.AreEqual(GetFolderPath(SpecialFolder.UserProfile), Other.Home); + } + + [TestMethod, TestCategory("Applications")] + public void Applications_MacOS_Default() + { + Helper.Prepare("DISCARD", null, "macOS"); + CollectionAssert.AreEquivalent(new string[] { "/Applications" }, (System.Collections.ICollection)Other.Applications); + } + + [TestMethod, TestCategory("Fonts")] + public void Fonts_MacOS_Default() + { + Helper.Prepare("DISCARD", null, "macOS"); + CollectionAssert.AreEquivalent(new string[] { $"{Other.Home}/Library/Fonts", "/Library/Fonts", "/System/Library/Fonts", "/Network/Library/Fonts" }, (System.Collections.ICollection)Other.Fonts); + } + } + + [TestClass, TestCategory("Linux")] + public class Linux + { + [TestMethod, TestCategory("Home")] + public void Home_Linux_Default() + { + Helper.Prepare("DISCARD", null, "Linux"); + Assert.AreEqual(GetEnvironmentVariable("HOME"), Other.Home); + } + + [TestMethod, TestCategory("Home")] + public void Home_Linux_NoHome() + { + Helper.Prepare("HOME", null, "Linux"); + Assert.AreEqual(GetFolderPath(SpecialFolder.UserProfile), Other.Home); + } + + [TestMethod, TestCategory("Applications")] + public void Applications_Linux_Default() + { + Helper.Prepare("DISCARD", null, "Linux"); + CollectionAssert.AreEquivalent(new string[] { $"{BaseDirectory.DataHome}/applications", $"{Other.Home}/.local/share/applications", "/usr/local/share/applications", "/usr/share/applications", }, (System.Collections.ICollection)Other.Applications); + } + + [TestMethod, TestCategory("Fonts")] + public void Fonts_Linux_Default() + { + Helper.Prepare("DISCARD", null, "Linux"); + CollectionAssert.AreEquivalent(new string[] { $"{BaseDirectory.DataHome}/fonts", $"{Other.Home}/.fonts", $"{Other.Home}/.local/share/fonts", "/usr/local/share/fonts", "/usr/share/fonts", }, (System.Collections.ICollection)Other.Fonts); + } + } +} diff --git a/src/Xdg.Testing/Directories/UserDirectory_test.cs b/src/Xdg.Testing/Directories/UserDirectory_test.cs new file mode 100644 index 0000000..c612792 --- /dev/null +++ b/src/Xdg.Testing/Directories/UserDirectory_test.cs @@ -0,0 +1,245 @@ +namespace Xdg.Directories.Testing.Directories; + +[TestClass] +public class UserDirectory_Test +{ + [TestClass, TestCategory("Windows")] + public class Windows + { + [TestMethod, TestCategory("DesktopDir")] + public void DesktopDir_Windows_Default() + { + Helper.Prepare("XDG_DESKTOP_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.Desktop), UserDirectory.DesktopDir); + } + + [TestMethod, TestCategory("DownloadDir")] + public void DownloadDir_Windows_Default() + { + Helper.Prepare("XDG_DOWNLOAD_DIR", null, "Windows"); + Assert.IsNull(UserDirectory.DownloadDir); + } + + [TestMethod, TestCategory("DocumentsDir")] + public void DocumentsDir_Windows_Default() + { + Helper.Prepare("XDG_DOCUMENTS_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.MyDocuments), UserDirectory.DocumentsDir); + } + + [TestMethod, TestCategory("MusicDir")] + public void MusicDir_Windows_Default() + { + Helper.Prepare("XDG_MUSIC_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.MyMusic), UserDirectory.MusicDir); + } + + [TestMethod, TestCategory("PicturesDir")] + public void PicturesDir_Windows_Default() + { + Helper.Prepare("XDG_PICTURES_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.MyPictures), UserDirectory.PicturesDir); + } + + [TestMethod, TestCategory("VideosDir")] + public void VideosDir_Windows_Default() + { + Helper.Prepare("XDG_VIDEOS_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.MyVideos), UserDirectory.VideosDir); + } + + [TestMethod, TestCategory("TemplatesDir")] + public void Templates_Windows_Default() + { + Helper.Prepare("XDG_TEMPLATES_DIR", null, "Windows"); + Assert.AreEqual(GetFolderPath(SpecialFolder.Templates), UserDirectory.TemplatesDir); + } + + [TestMethod, TestCategory("PublicDir")] + public void Public_Windows_Default() + { + Helper.Prepare("XDG_PUBLICSHARE_DIR", null, "Windows"); + Assert.AreEqual(GetEnvironmentVariable("PUBLIC"), UserDirectory.PublicDir); + } + } + + [TestClass, TestCategory("MacOS")] + public class MacOS + { + [TestMethod, TestCategory("DesktopDir")] + public void DesktopDir_MacOS_Default() + { + Helper.Prepare("XDG_DESKTOP_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Desktop", UserDirectory.DesktopDir); + } + + [TestMethod, TestCategory("DownloadDir")] + public void DownloadDir_MacOS_Default() + { + Helper.Prepare("XDG_DOWNLOAD_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Downloads", UserDirectory.DownloadDir); + } + + [TestMethod, TestCategory("DocumentsDir")] + public void DocumentsDir_MacOS_Default() + { + Helper.Prepare("XDG_DOCUMENTS_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Documents", UserDirectory.DocumentsDir); + } + + [TestMethod, TestCategory("MusicDir")] + public void MusicDir_MacOS_Default() + { + Helper.Prepare("XDG_MUSIC_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Music", UserDirectory.MusicDir); + } + + [TestMethod, TestCategory("PicturesDir")] + public void PicturesDir_MacOS_Default() + { + Helper.Prepare("XDG_PICTURES_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Pictures", UserDirectory.PicturesDir); + } + + [TestMethod, TestCategory("VideosDir")] + public void VideosDir_MacOS_Default() + { + Helper.Prepare("XDG_VIDEOS_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Movies", UserDirectory.VideosDir); + } + + [TestMethod, TestCategory("TemplatesDir")] + public void TemplatesDir_MacOS_Default() + { + Helper.Prepare("XDG_TEMPLATES_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Templates", UserDirectory.TemplatesDir); + } + + [TestMethod, TestCategory("PublicDir")] + public void PublicDir_MacOS_Default() + { + Helper.Prepare("XDG_PUBLIC_DIR", null, "MacOS"); + Assert.AreEqual($"{Other.Home}/Public", UserDirectory.PublicDir); + } + } + + [TestClass, TestCategory("Linux")] + public class Linux + { + [TestMethod, TestCategory("DesktopDir")] + public void DesktopDir_Linux_Default() + { + Helper.Prepare("XDG_DESKTOP_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Desktop", UserDirectory.DesktopDir); + } + + [TestMethod, TestCategory("DownloadDir")] + public void DownloadDir_Linux_Default() + { + Helper.Prepare("XDG_DOWNLOAD_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Downloads", UserDirectory.DownloadDir); + } + + [TestMethod, TestCategory("DocumentsDir")] + public void DocumentsDir_Linux_Default() + { + Helper.Prepare("XDG_DOCUMENTS_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Documents", UserDirectory.DocumentsDir); + } + + [TestMethod, TestCategory("MusicDir")] + public void MusicDir_Linux_Default() + { + Helper.Prepare("XDG_MUSIC_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Music", UserDirectory.MusicDir); + } + + [TestMethod, TestCategory("PicturesDir")] + public void PicturesDir_Linux_Default() + { + Helper.Prepare("XDG_PICTURES_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Pictures", UserDirectory.PicturesDir); + } + + [TestMethod, TestCategory("VideosDir")] + public void VideosDir_Linux_Default() + { + Helper.Prepare("XDG_VIDEOS_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Videos", UserDirectory.VideosDir); + } + + [TestMethod, TestCategory("TemplatesDir")] + public void TemplatesDir_Linux_Default() + { + Helper.Prepare("XDG_TEMPLATES_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Templates", UserDirectory.TemplatesDir); + } + + [TestMethod, TestCategory("PublicDir")] + public void PublicDir_Linux_Default() + { + Helper.Prepare("XDG_PUBLIC_DIR", null, "Linux"); + Assert.AreEqual($"{Other.Home}/Public", UserDirectory.PublicDir); + } + } + + [TestClass, TestCategory("SetEnv")] + public class Env + { + [TestMethod, TestCategory("DesktopDir")] + public void DesktopDir_SetEnv() + { + SetEnvironmentVariable("XDG_DESKTOP_DIR", "/"); + Assert.AreEqual("/", UserDirectory.DesktopDir); + } + + [TestMethod, TestCategory("DownloadDir")] + public void DownloadDir_SetEnv() + { + SetEnvironmentVariable("XDG_DOWNLOAD_DIR", "/"); + Assert.AreEqual("/", UserDirectory.DownloadDir); + } + + [TestMethod, TestCategory("DocumentsDir")] + public void DocumentsDir_SetEnv() + { + SetEnvironmentVariable("XDG_DOCUMENTS_DIR", "/"); + Assert.AreEqual("/", UserDirectory.DocumentsDir); + } + + [TestMethod, TestCategory("MusicDir")] + public void MusicDir_SetEnv() + { + SetEnvironmentVariable("XDG_MUSIC_DIR", "/"); + Assert.AreEqual("/", UserDirectory.MusicDir); + } + + [TestMethod, TestCategory("PicturesDir")] + public void PicturesDir_SetEnv() + { + SetEnvironmentVariable("XDG_PICTURES_DIR", "/"); + Assert.AreEqual("/", UserDirectory.PicturesDir); + } + + [TestMethod, TestCategory("VideosDir")] + public void VideosDir_SetEnv() + { + SetEnvironmentVariable("XDG_VIDEOS_DIR", "/"); + Assert.AreEqual("/", UserDirectory.VideosDir); + } + + [TestMethod, TestCategory("TemplatesDir")] + public void Templates_SetEnv() + { + SetEnvironmentVariable("XDG_TEMPLATES_DIR", "/"); + Assert.AreEqual("/", UserDirectory.TemplatesDir); + } + + [TestMethod, TestCategory("PublicDir")] + public void Public_SetEnv() + { + SetEnvironmentVariable("XDG_PUBLICSHARE_DIR", "/"); + Assert.AreEqual("/", UserDirectory.PublicDir); + } + } +} \ No newline at end of file diff --git a/src/Xdg.Testing/Usings.cs b/src/Xdg.Testing/Usings.cs new file mode 100644 index 0000000..99b2ca9 --- /dev/null +++ b/src/Xdg.Testing/Usings.cs @@ -0,0 +1,2 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using static System.Environment; \ No newline at end of file diff --git a/src/Xdg.Testing/Xdg.Testing.csproj b/src/Xdg.Testing/Xdg.Testing.csproj new file mode 100644 index 0000000..c947614 --- /dev/null +++ b/src/Xdg.Testing/Xdg.Testing.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + + false + true + false + + + + + + + + + + + + + +