using System; using System.Collections.Generic; using System.IO; using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using Xunit; using Xunit.Extensions; namespace LibGit2Sharp.Tests { public class ConfigurationFixture : BaseFixture { private static void AssertValueInLocalConfigFile(string repoPath, string regex) { var configFilePath = Path.Combine(repoPath, ".git/config"); AssertValueInConfigFile(configFilePath, regex); } [Fact] public void CanUnsetAnEntryFromTheLocalConfiguration() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { Assert.Null(repo.Config.Get("unittests.boolsetting")); repo.Config.Set("unittests.boolsetting", true); Assert.True(repo.Config.Get("unittests.boolsetting").Value); repo.Config.Unset("unittests.boolsetting"); Assert.Null(repo.Config.Get("unittests.boolsetting")); } } [Fact] public void CanUnsetAnEntryFromTheGlobalConfiguration() { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); var options = BuildFakeConfigs(scd); string path = SandboxBareTestRepo(); using (var repo = new Repository(path, options)) { Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global)); Assert.Equal(42, repo.Config.Get("Wow.Man-I-am-totally-global").Value); repo.Config.Unset("Wow.Man-I-am-totally-global"); Assert.Equal(42, repo.Config.Get("Wow.Man-I-am-totally-global").Value); repo.Config.Unset("Wow.Man-I-am-totally-global", ConfigurationLevel.Global); Assert.Null(repo.Config.Get("Wow.Man-I-am-totally-global")); } } [Fact] public void CanReadBooleanValue() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.True(repo.Config.Get("core.ignorecase").Value); Assert.True(repo.Config.GetValueOrDefault("core.ignorecase")); Assert.Equal(false, repo.Config.GetValueOrDefault("missing.key")); Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", true)); Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", () => true)); } } [Fact] public void CanReadIntValue() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Equal(2, repo.Config.Get("unittests.intsetting").Value); Assert.Equal(2, repo.Config.GetValueOrDefault("unittests.intsetting")); Assert.Equal(2, repo.Config.GetValueOrDefault("unittests.intsetting", ConfigurationLevel.Local)); Assert.Equal(0, repo.Config.GetValueOrDefault("missing.key")); Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", 4)); Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", () => 4)); } } [Fact] public void CanReadLongValue() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Equal(15234, repo.Config.Get("unittests.longsetting").Value); Assert.Equal(15234, repo.Config.GetValueOrDefault("unittests.longsetting")); Assert.Equal(0, repo.Config.GetValueOrDefault("missing.key")); Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", 4)); Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", () => 4)); } } [Fact] public void CanReadStringValue() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.Get("remote.origin.fetch").Value); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.Get("remote", "origin", "fetch").Value); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote.origin.fetch")); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote.origin.fetch", ConfigurationLevel.Local)); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote", "origin", "fetch")); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault(new[] { "remote", "origin", "fetch" })); Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key")); Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", default(string))); Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", default(Func))); Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", "value")); Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", () => "value")); Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local)); Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(string))); Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(Func))); Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, "value")); Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, () => "value")); Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key")); Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key", default(string))); Assert.Throws(() => repo.Config.GetValueOrDefault("missing", "config", "key", default(Func))); Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", "value")); Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", () => "value")); Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" })); Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(string))); Assert.Throws(() => repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(Func))); Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, "value")); Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, () => "value")); } } [Fact] public void CanEnumerateGlobalConfig() { string configPath = CreateConfigurationWithDummyUser(Constants.Identity); var options = new RepositoryOptions { GlobalConfigurationLocation = configPath }; var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path, options)) { var entry = repo.Config.FirstOrDefault>(e => e.Key == "user.name"); Assert.NotNull(entry); Assert.Equal(Constants.Signature.Name, entry.Value); } } [Fact] public void CanEnumerateLocalConfig() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { var entry = repo.Config.FirstOrDefault>(e => e.Key == "core.ignorecase"); Assert.NotNull(entry); Assert.Equal("true", entry.Value); } } [Fact] public void CanEnumerateLocalConfigContainingAKeyWithNoValue() { string path = SandboxBareTestRepo(); using (var repo = new Repository(path)) { var entry = repo.Config .Single>(c => c.Level == ConfigurationLevel.Local && c.Key == "core.pager"); Assert.Equal(string.Empty, entry.Value); } } [Fact] public void CanFindInLocalConfig() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { var matches = repo.Config.Find("unit"); Assert.NotNull(matches); Assert.Equal(new[] { "unittests.intsetting", "unittests.longsetting" }, matches .Select(m => m.Key) .OrderBy(s => s) .ToArray()); } } [Fact] public void CanFindInGlobalConfig() { string configPath = CreateConfigurationWithDummyUser(Constants.Identity); var options = new RepositoryOptions { GlobalConfigurationLocation = configPath }; var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path, options)) { var matches = repo.Config.Find(@"\.name", ConfigurationLevel.Global); Assert.NotNull(matches); Assert.Equal(new[] { "user.name" }, matches.Select(m => m.Key).ToArray()); } } [Fact] public void CanSetBooleanValue() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { repo.Config.Set("unittests.boolsetting", true); AssertValueInLocalConfigFile(path, "boolsetting = true$"); } } [Fact] public void SettingLocalConfigurationOutsideAReposThrows() { using (var config = Configuration.BuildFrom(null, null, null, null)) { Assert.Throws(() => config.Set("unittests.intsetting", 3)); } } [Fact] public void CanSetIntValue() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { repo.Config.Set("unittests.intsetting", 3); AssertValueInLocalConfigFile(path, "intsetting = 3$"); } } [Fact] public void CanSetLongValue() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { repo.Config.Set("unittests.longsetting", (long)451); AssertValueInLocalConfigFile(path, "longsetting = 451"); } } [Fact] public void CanSetStringValue() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { repo.Config.Set("unittests.stringsetting", "val"); AssertValueInLocalConfigFile(path, "stringsetting = val$"); } } [Fact] public void CanSetAndReadUnicodeStringValue() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { repo.Config.Set("unittests.stringsetting", "Juliën"); AssertValueInLocalConfigFile(path, "stringsetting = Juliën$"); string val = repo.Config.Get("unittests.stringsetting").Value; Assert.Equal("Juliën", val); } // Make sure the change is permanent using (var repo = new Repository(path)) { string val = repo.Config.Get("unittests.stringsetting").Value; Assert.Equal("Juliën", val); } } [Fact] public void ReadingUnsupportedTypeThrows() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Throws(() => repo.Config.Get("unittests.setting")); Assert.Throws(() => repo.Config.Get("unittests.setting")); } } [Fact] public void ReadingValueThatDoesntExistReturnsNull() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Null(repo.Config.Get("unittests.ghostsetting")); Assert.Null(repo.Config.Get("unittests.ghostsetting")); Assert.Null(repo.Config.Get("unittests.ghostsetting")); Assert.Null(repo.Config.Get("unittests.ghostsetting")); } } [Fact] public void SettingUnsupportedTypeThrows() { var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { Assert.Throws(() => repo.Config.Set("unittests.setting", (short)123)); Assert.Throws(() => repo.Config.Set("unittests.setting", repo.Config)); } } [Fact] public void CanGetAnEntryFromASpecificStore() { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); var options = BuildFakeConfigs(scd); string path = SandboxStandardTestRepo(); using (var repo = new Repository(path, options)) { Assert.True(repo.Config.HasConfig(ConfigurationLevel.Local)); Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global)); Assert.True(repo.Config.HasConfig(ConfigurationLevel.System)); Assert.Null(repo.Config.Get("Woot.global-rocks", ConfigurationLevel.Local)); repo.Config.Set("Woot.this-rocks", "local"); Assert.Equal("global", repo.Config.Get("Woot.this-rocks", ConfigurationLevel.Global).Value); Assert.Equal("xdg", repo.Config.Get("Woot.this-rocks", ConfigurationLevel.Xdg).Value); Assert.Equal("system", repo.Config.Get("Woot.this-rocks", ConfigurationLevel.System).Value); Assert.Equal("local", repo.Config.Get("Woot.this-rocks", ConfigurationLevel.Local).Value); } } [Fact] public void CanTellIfASpecificStoreContainsAKey() { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); var options = BuildFakeConfigs(scd); string path = SandboxBareTestRepo(); using (var repo = new Repository(path, options)) { Assert.True(repo.Config.HasConfig(ConfigurationLevel.System)); Assert.Null(repo.Config.Get("MCHammer.You-cant-touch-this", ConfigurationLevel.System)); } } public static IEnumerable ConfigAccessors { get { return new List { new[] { new Func(p => Path.Combine(p, ".git", "config")) }, new[] { new Func(p => Path.Combine(p, ".git")) }, new[] { new Func(p => p) }, }; } } [Theory, PropertyData("ConfigAccessors")] public void CanAccessConfigurationWithoutARepository(Func localConfigurationPathProvider) { var path = SandboxStandardTestRepoGitDir(); string globalConfigPath = CreateConfigurationWithDummyUser(Constants.Identity); var options = new RepositoryOptions { GlobalConfigurationLocation = globalConfigPath }; using (var repo = new Repository(path, options)) { repo.Config.Set("my.key", "local"); repo.Config.Set("my.key", "mouse", ConfigurationLevel.Global); } using (var config = Configuration.BuildFrom(localConfigurationPathProvider(path), globalConfigPath)) { Assert.Equal("local", config.Get("my.key").Value); Assert.Equal("mouse", config.Get("my.key", ConfigurationLevel.Global).Value); } } [Fact] public void PassingANonExistingLocalConfigurationFileToBuildFromthrowss() { Assert.Throws(() => Configuration.BuildFrom( Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()))); } [Theory] [InlineData(null, "x@example.com")] [InlineData("", "x@example.com")] [InlineData("X", null)] [InlineData("X", "")] public void CannotBuildAProperSignatureFromConfigWhenFullIdentityCannotBeFoundInTheConfig(string name, string email) { string repoPath = InitNewRepository(); string configPath = CreateConfigurationWithDummyUser(name, email); var options = new RepositoryOptions { GlobalConfigurationLocation = configPath }; using (var repo = new Repository(repoPath, options)) { Assert.Equal(name, repo.Config.GetValueOrDefault("user.name")); Assert.Equal(email, repo.Config.GetValueOrDefault("user.email")); Signature signature = repo.Config.BuildSignature(DateTimeOffset.Now); Assert.Null(signature); } } [Fact] public void CanSetAndGetSearchPath() { string globalPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()); string systemPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()); string xdgPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()); GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, globalPath); GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, systemPath); GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Xdg, xdgPath); Assert.Equal(globalPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global).Single()); Assert.Equal(systemPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.System).Single()); Assert.Equal(xdgPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Xdg).Single()); // reset the search paths to their defaults GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, null); GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Xdg, null); } [Fact] public void CanSetAndGetMultipleSearchPaths() { string[] paths = { Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()), Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()), Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()), }; GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, paths); Assert.Equal(paths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global)); // set back to the defaults GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); } [Fact] public void CanResetSearchPaths() { // all of these calls should reset the config path to the default Action[] resetActions = { () => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global), () => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null), () => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, string.Empty), () => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, new string[] { }), }; // record the default search path GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); var oldPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global); Assert.NotNull(oldPaths); // generate a non-default path to set var newPaths = new string[] { Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()) }; foreach (var tryToReset in resetActions) { // change to the non-default path GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, newPaths); Assert.Equal(newPaths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global)); // set it back to the default tryToReset(); Assert.Equal(oldPaths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global)); } // make sure the config paths are reset after the test ends GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); } [Fact] public void CanAppendToSearchPaths() { string appendMe = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()); var prevPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global); // append using the special name $PATH GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, "$PATH", appendMe); var currentPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global); Assert.Equal(currentPaths, prevPaths.Concat(new[] { appendMe })); // set it back to the default GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); } [Fact] public void CanRedirectConfigAccess() { var scd1 = BuildSelfCleaningDirectory(); var scd2 = BuildSelfCleaningDirectory(); Touch(scd1.RootedDirectoryPath, ".gitconfig"); Touch(scd2.RootedDirectoryPath, ".gitconfig"); // redirect global access to the first path GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, scd1.RootedDirectoryPath); // set a value in the first config using (var config = Configuration.BuildFrom(null)) { config.Set("luggage.code", 9876, ConfigurationLevel.Global); Assert.Equal(9876, config.Get("luggage.code", ConfigurationLevel.Global).Value); } // redirect global config access to path2 GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, scd2.RootedDirectoryPath); // if the redirect succeeds, the value set in the prior config should not be visible using (var config = Configuration.BuildFrom(null)) { Assert.Equal(-1, config.GetValueOrDefault("luggage.code", ConfigurationLevel.Global, -1)); } // reset the search path to the default GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); } } }