Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ResourceIdentifier fixes and enhancements #15656

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/Bicep.IO.UnitTests/Abstraction/ResourceIdentifierExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using Bicep.IO.Abstraction;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Bicep.IO.UnitTests.Abstraction
{
[TestClass]
public class ResourceIdentifierExtensionsTests
{
[DataTestMethod]
[DataRow("/a/b/c.txt", ".txt")]
[DataRow("/a/b/c.tar.gz", ".gz")]
[DataRow("/a/b/c", "")]
[DataRow("/a/b/c.", "")]
[DataRow("/a/b/c.d/e", "")]
public void GetExtension_ValidPaths_ReturnsCorrectExtension(string path, string expectedExtension)
{
// Arrange.
var resourceIdentifier = new ResourceIdentifier("file", "", path);

// Act.
var extension = resourceIdentifier.GetExtension();

// Assert.
extension.ToString().Should().Be(expectedExtension);
}

[DataTestMethod]
[DataRow("/a/b/c.txt", ".bak", "/a/b/c.bak")]
[DataRow("/a/b/c.tar.gz", ".zip", "/a/b/c.tar.zip")]
[DataRow("/a/b/c.tar.gz", "zip", "/a/b/c.tar.zip")]
[DataRow("/a/b/c", ".txt", "/a/b/c.txt")]
[DataRow("/a/b/c.", ".txt", "/a/b/c.txt")]
[DataRow("/a/b/c.d/e", ".txt", "/a/b/c.d/e.txt")]
public void WithExtension_ValidPaths_ReturnsPathWithNewExtension(string path, string newExtension, string expectedPath)
{
// Arrange
var resourceIdentifier = new ResourceIdentifier("file", "", path);

// Act
var newResourceIdentifier = resourceIdentifier.WithExtension(newExtension);

// Assert
newResourceIdentifier.Path.Should().Be(expectedPath);
}
}
}
187 changes: 160 additions & 27 deletions src/Bicep.IO.UnitTests/Abstraction/ResourceIdentifierTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,95 +7,228 @@
using System.Text;
using System.Threading.Tasks;
using Bicep.IO.Abstraction;
using FluentAssertions;

namespace Bicep.IO.UnitTests.Abstraction
{
[TestClass]
public class ResourceIdentifierTests
{
[DataTestMethod]
[DataRow("http", "EXAMPLE.COM", "example.com")]
[DataRow("http", "Example.Com", "example.com")]
[DataRow("http", "example.com", "example.com")]
[DataRow("https", "EXAMPLE.COM:80", "example.com:80")]
[DataRow("https", "Example.Com:443", "example.com:443")]
[DataRow("file", "localhost", "")]
[DataRow("file", "", "")]
[DataRow("file", null, "")]
public void ResourceIdentifier_ByDefault_NormalizesAuthority(string scheme, string? authority, string expectedAuthority)
{
// Arrange & Act.
var resourceIdentifier = new ResourceIdentifier(scheme, authority, "/a/b/c");

// Assert.
resourceIdentifier.Authority.Should().Be(expectedAuthority);
}

[DataTestMethod]
[DataRow("/a/b/c", "/a/b/c")]
[DataRow("/a/b/../c", "/a/c")]
[DataRow("/a/./b/c", "/a/b/c")]
[DataRow("/a/b/c/", "/a/b/c/")]
[DataRow("/a//b/c", "/a/b/c")]
[DataRow("/a/b/c/..", "/a/b")]
public void ResourceIdentifier_ByDefault_CanonicalizePath(string inputPath, string expectedPath)
public void ResourceIdentifier_ByDefault_NormalizesPath(string inputPath, string expectedPath)
{
// Act
// Arrange & Act.
var resourceIdentifier = new ResourceIdentifier("http", "example.com", inputPath);

// Assert
Assert.AreEqual(expectedPath, resourceIdentifier.Path);
// Assert.
resourceIdentifier.Path.Should().Be(expectedPath);
}

[DataTestMethod]
[DataRow("https", "")]
[DataRow("https", null)]
[DataRow("http", "")]
[DataRow("http", null)]
public void ResourceIdentifier_NullOrEmptyHttpOrHttpsAuthority_ThrowsArgumentException(string scheme, string? authority)
{
FluentActions
.Invoking(() => new ResourceIdentifier(scheme, authority, "/a/b/c"))
.Should().Throw<ArgumentException>();
}

[DataTestMethod]
[DataRow("http", "example.com", "a/b/c")]
[DataRow("http", null, "//a/b/c")]
[DataRow("file", null, "a/b/c")]
public void ResourceIdentifier_InvalidPath_ThrowsArgumentException(string scheme, string? authorty, string path)
{
FluentActions
.Invoking(() => new ResourceIdentifier(scheme, authorty, path))
.Should().Throw<ArgumentException>();
}

[DataTestMethod]
[DataRow("http", "example.com", "/a/b/c", "http://example.com/a/b/c")]
[DataRow("https", "example.com", "/a/b/c", "https://example.com/a/b/c")]
[DataRow("file", "", "/a/b/c", "/a/b/c")]
public void ResourceIdentifier_ToString_ReturnsCorrectUriOrPath(string scheme, string authority, string path, string expectedOutput)
public void ToString_ByDefault_ReturnsUriOrLocalFilePath(string scheme, string authority, string path, string expectedOutput)
{
// Act
// Arrange & Act.
var resourceIdentifier = new ResourceIdentifier(scheme, authority, path);

// Assert
Assert.AreEqual(expectedOutput, resourceIdentifier.ToString());
resourceIdentifier.ToString().Should().Be(expectedOutput);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ResourceIdentifier_InvalidPath_ThrowsArgumentException()
{
// Act
var resourceIdentifier = new ResourceIdentifier("http", "example.com", "a/b/c");
}

[TestMethod]
public void ResourceIdentifier_Equals_ReturnsTrueForIdenticalIdentifiers()
public void Equals_IdenticalIdentifiers_ReturnsTrue()
{
// Arrange
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("http", "example.com", "/a/b/c");

// Act & Assert
Assert.IsTrue(identifier1.Equals(identifier2));
Assert.IsTrue(identifier1 == identifier2);
Assert.IsFalse(identifier1 != identifier2);
identifier1.Equals(identifier2).Should().BeTrue();
(identifier1 == identifier2).Should().BeTrue();
(identifier1 != identifier2).Should().BeFalse();
}

[TestMethod]
public void ResourceIdentifier_Equals_ReturnsFalseForDifferentIdentifiers()
public void Equals_DifferentIdentifiers_ReturnsFalse()
{
// Arrange
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("http", "example.com", "/a/b/d");

// Act & Assert
Assert.IsFalse(identifier1.Equals(identifier2));
Assert.IsFalse(identifier1 == identifier2);
Assert.IsTrue(identifier1 != identifier2);
identifier1.Equals(identifier2).Should().BeFalse();
(identifier1 == identifier2).Should().BeFalse();
(identifier1 != identifier2).Should().BeTrue();
}

[TestMethod]
public void ResourceIdentifier_GetHashCode_ReturnsConsistentHashCode()
public void GetHashCode_IdenticalIdentifiers_ReturnsConsistentHashCode()
{
// Arrange
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("http", "example.com", "/a/b/c");

// Act & Assert
Assert.AreEqual(identifier1.GetHashCode(), identifier2.GetHashCode());
identifier1.GetHashCode().Should().Be(identifier2.GetHashCode());
}

[TestMethod]
public void ResourceIdentifier_GetHashCode_ReturnsDifferentHashCodesForDifferentIdentifiers()
public void GetHashCode_DifferentIdentifiers_ReturnsDifferentHashCodes()
{
// Arrange
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("http", "example.com", "/a/b/d");

// Act & Assert
Assert.AreNotEqual(identifier1.GetHashCode(), identifier2.GetHashCode());
identifier1.GetHashCode().Should().NotBe(identifier2.GetHashCode());
}

[DataTestMethod]
[DataRow("http", "example.com", "/a/b/c", "/a/b", "c")]
[DataRow("http", "example.com", "/a/b/c/", "/a/b", "c/")]
[DataRow("http", "example.com", "/a/b/c", "/a/b/c", "")]
[DataRow("http", "example.com", "/a/b/c", "/a/b/d", "../c")]
[DataRow("http", "example.com", "/a/b/c/d", "/a/b", "c/d")]
[DataRow("http", "example.com", "/a/b/c", "/a/b/c/d", "..")]
public void GetPathRelativeTo_ValidPaths_ReturnsCorrectRelativePath(string scheme, string authority, string path, string otherPath, string expectedRelativePath)
{
// Arrange.
var identifier = new ResourceIdentifier(scheme, authority, path);
var otherIdentifier = new ResourceIdentifier(scheme, authority, otherPath);

// Act.
var relativePath = identifier.GetPathRelativeTo(otherIdentifier);

// Assert.
relativePath.Should().Be(expectedRelativePath);
}

[TestMethod]
public void GetPathRelativeTo_DifferentSchemes_ThrowsInvalidOperationException()
{
// Arrange.
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("https", "example.com", "/a/b/c");

// Act.
Action act = () => identifier1.GetPathRelativeTo(identifier2);

// Assert.
act.Should().Throw<InvalidOperationException>();
}

[TestMethod]
public void GetPathRelativeTo_DifferentAuthorities_ThrowsInvalidOperationException()
{
// Arrange.
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b/c");
var identifier2 = new ResourceIdentifier("http", "example.org", "/a/b/c");

// Act.
Action act = () => identifier1.GetPathRelativeTo(identifier2);

// Assert.
act.Should().Throw<InvalidOperationException>();
}

[DataTestMethod]
[DataRow("http", "example.com", "/a/b", "/a/b/c", true)]
[DataRow("http", "example.com", "/a/b", "/a/b/c/d", true)]
[DataRow("http", "example.com", "/a/b", "/a/b", true)]
[DataRow("http", "example.com", "/a/b", "/a/c", false)]
[DataRow("http", "example.com", "/a/b", "/a/bc", false)]
[DataRow("http", "example.com", "/a/b", "/a/bc/d", false)]
[DataRow("http", "example.com", "/a/b", "/a/b/../c", false)]
[DataRow("http", "example.com", "/a/b", "/a/b/./c", true)]
[DataRow("http", "example.com", "/a/b", "/a/b/c/..", true)]
public void IsBaseOf_ValidPaths_ReturnsExpectedResult(string scheme, string authority, string basePath, string otherPath, bool expectedResult)
{
// Arrange.
var baseIdentifier = new ResourceIdentifier(scheme, authority, basePath);
var otherIdentifier = new ResourceIdentifier(scheme, authority, otherPath);

// Act.
var result = baseIdentifier.IsBaseOf(otherIdentifier);

// Assert.
result.Should().Be(expectedResult);
}

[TestMethod]
public void IsBaseOf_DifferentSchemes_ReturnsFalse()
{
// Arrange.
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b");
var identifier2 = new ResourceIdentifier("https", "example.com", "/a/b/c");

// Act.
var result = identifier1.IsBaseOf(identifier2);

// Assert.
result.Should().BeFalse();
}

[TestMethod]
public void IsBaseOf_DifferentAuthorities_ReturnsFalse()
{
// Arrange.
var identifier1 = new ResourceIdentifier("http", "example.com", "/a/b");
var identifier2 = new ResourceIdentifier("http", "example.org", "/a/b/c");

// Act.
var result = identifier1.IsBaseOf(identifier2);

// Assert.
result.Should().BeFalse();
}
}
}
Loading
Loading