|  | #region Copyright notice and license | 
|  |  | 
|  | // Copyright 2018 gRPC authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #endregion | 
|  |  | 
|  | using System.IO; | 
|  | using Microsoft.Build.Framework; | 
|  | using Microsoft.Build.Utilities; | 
|  | using NUnit.Framework; | 
|  |  | 
|  | namespace Grpc.Tools.Tests | 
|  | { | 
|  | public class DepFileUtilTest | 
|  | { | 
|  |  | 
|  | [Test] | 
|  | public void HashString64Hex_IsSane() | 
|  | { | 
|  | string hashFoo1 = DepFileUtil.HashString64Hex("foo"); | 
|  | string hashEmpty = DepFileUtil.HashString64Hex(""); | 
|  | string hashFoo2 = DepFileUtil.HashString64Hex("foo"); | 
|  |  | 
|  | StringAssert.IsMatch("^[a-f0-9]{16}$", hashFoo1); | 
|  | Assert.AreEqual(hashFoo1, hashFoo2); | 
|  | Assert.AreNotEqual(hashFoo1, hashEmpty); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void GetDepFilenameForProto_IsSane() | 
|  | { | 
|  | StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}_foo.protodep$", | 
|  | DepFileUtil.GetDepFilenameForProto("out", "foo.proto")); | 
|  | StringAssert.IsMatch(@"^[a-f0-9]{16}_foo.protodep$", | 
|  | DepFileUtil.GetDepFilenameForProto("", "foo.proto")); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void GetDepFilenameForProto_HashesDir() | 
|  | { | 
|  | string PickHash(string fname) => | 
|  | DepFileUtil.GetDepFilenameForProto("", fname).Substring(0, 16); | 
|  |  | 
|  | string same1 = PickHash("dir1/dir2/foo.proto"); | 
|  | string same2 = PickHash("dir1/dir2/proto.foo"); | 
|  | string same3 = PickHash("dir1/dir2/proto"); | 
|  | string same4 = PickHash("dir1/dir2/.proto"); | 
|  | string unsame1 = PickHash("dir2/foo.proto"); | 
|  | string unsame2 = PickHash("/dir2/foo.proto"); | 
|  |  | 
|  | Assert.AreEqual(same1, same2); | 
|  | Assert.AreEqual(same1, same3); | 
|  | Assert.AreEqual(same1, same4); | 
|  | Assert.AreNotEqual(same1, unsame1); | 
|  | Assert.AreNotEqual(unsame1, unsame2); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void GetOutputDirWithHash_IsSane() | 
|  | { | 
|  | StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}$", | 
|  | DepFileUtil.GetOutputDirWithHash("out", "foo.proto")); | 
|  | StringAssert.IsMatch(@"^[a-f0-9]{16}$", | 
|  | DepFileUtil.GetOutputDirWithHash("", "foo.proto")); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void GetOutputDirWithHash_HashesDir() | 
|  | { | 
|  | string PickHash(string fname) => DepFileUtil.GetOutputDirWithHash("", fname); | 
|  |  | 
|  | string same1 = PickHash("dir1/dir2/foo.proto"); | 
|  | string same2 = PickHash("dir1/dir2/proto.foo"); | 
|  | string same3 = PickHash("dir1/dir2/proto"); | 
|  | string same4 = PickHash("dir1/dir2/.proto"); | 
|  | string unsame1 = PickHash("dir2/foo.proto"); | 
|  | string unsame2 = PickHash("/dir2/foo.proto"); | 
|  |  | 
|  | Assert.AreEqual(same1, same2); | 
|  | Assert.AreEqual(same1, same3); | 
|  | Assert.AreEqual(same1, same4); | 
|  | Assert.AreNotEqual(same1, unsame1); | 
|  | Assert.AreNotEqual(unsame1, unsame2); | 
|  | } | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////// | 
|  | // Full file reading tests | 
|  |  | 
|  | // Generated by protoc on Windows. Slashes vary. | 
|  | const string depFile1 = | 
|  | @"C:\projects\foo\src\./foo.grpc.pb.cc \ | 
|  | C:\projects\foo\src\./foo.grpc.pb.h \ | 
|  | C:\projects\foo\src\./foo.pb.cc \ | 
|  | C:\projects\foo\src\./foo.pb.h: C:/usr/include/google/protobuf/wrappers.proto\ | 
|  | C:/usr/include/google/protobuf/any.proto\ | 
|  | C:/usr/include/google/protobuf/source_context.proto\ | 
|  | C:/usr/include/google/protobuf/type.proto\ | 
|  | foo.proto"; | 
|  |  | 
|  | // This has a nasty output directory with a space. | 
|  | const string depFile2 = | 
|  | @"obj\Release x64\net45\/Foo.cs \ | 
|  | obj\Release x64\net45\/FooGrpc.cs: C:/usr/include/google/protobuf/wrappers.proto\ | 
|  | C:/projects/foo/src//foo.proto"; | 
|  |  | 
|  | [Test] | 
|  | public void ReadDependencyInput_FullFile1() | 
|  | { | 
|  | string[] deps = ReadDependencyInputFromFileData(depFile1, "foo.proto"); | 
|  |  | 
|  | Assert.NotNull(deps); | 
|  | Assert.That(deps, Has.Length.InRange(4, 5));  // foo.proto may or may not be listed. | 
|  | Assert.That(deps, Has.One.EndsWith("wrappers.proto")); | 
|  | Assert.That(deps, Has.One.EndsWith("type.proto")); | 
|  | Assert.That(deps, Has.None.StartWith(" ")); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void ReadDependencyInput_FullFile2() | 
|  | { | 
|  | string[] deps = ReadDependencyInputFromFileData(depFile2, "C:/projects/foo/src/foo.proto"); | 
|  |  | 
|  | Assert.NotNull(deps); | 
|  | Assert.That(deps, Has.Length.InRange(1, 2)); | 
|  | Assert.That(deps, Has.One.EndsWith("wrappers.proto")); | 
|  | Assert.That(deps, Has.None.StartWith(" ")); | 
|  | } | 
|  |  | 
|  | [Test] | 
|  | public void ReadDependencyInput_FullFileUnparsable() | 
|  | { | 
|  | string[] deps = ReadDependencyInputFromFileData("a:/foo.proto", "/foo.proto"); | 
|  | Assert.NotNull(deps); | 
|  | Assert.Zero(deps.Length); | 
|  | } | 
|  |  | 
|  | private string[] ReadDependencyInputFromFileData(string fileData, string protoName) | 
|  | { | 
|  | string randomTempDir = Path.GetTempPath() + '/' + Path.GetRandomFileName(); | 
|  | Directory.CreateDirectory(randomTempDir); | 
|  | string tempfile = DepFileUtil.GetDepFilenameForProto(randomTempDir, protoName); | 
|  | try | 
|  | { | 
|  | File.WriteAllText(tempfile, fileData); | 
|  | var mockEng = new Moq.Mock<IBuildEngine>(); | 
|  | var log = new TaskLoggingHelper(mockEng.Object, "x"); | 
|  | return DepFileUtil.ReadDependencyInputs(randomTempDir, protoName, log); | 
|  | } | 
|  | finally | 
|  | { | 
|  | try | 
|  | { | 
|  | File.Delete(tempfile); | 
|  | } | 
|  | catch { } | 
|  | } | 
|  | } | 
|  | }; | 
|  | } |