1 #region Copyright notice and license 2 3 // Copyright 2018 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System.IO; 20 using Microsoft.Build.Framework; 21 using Microsoft.Build.Utilities; 22 using NUnit.Framework; 23 24 namespace Grpc.Tools.Tests 25 { 26 public class DepFileUtilTest 27 { 28 29 [Test] HashString64Hex_IsSane()30 public void HashString64Hex_IsSane() 31 { 32 string hashFoo1 = DepFileUtil.HashString64Hex("foo"); 33 string hashEmpty = DepFileUtil.HashString64Hex(""); 34 string hashFoo2 = DepFileUtil.HashString64Hex("foo"); 35 36 StringAssert.IsMatch("^[a-f0-9]{16}$", hashFoo1); 37 Assert.AreEqual(hashFoo1, hashFoo2); 38 Assert.AreNotEqual(hashFoo1, hashEmpty); 39 } 40 41 [Test] GetDepFilenameForProto_IsSane()42 public void GetDepFilenameForProto_IsSane() 43 { 44 StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}_foo.protodep$", 45 DepFileUtil.GetDepFilenameForProto("out", "foo.proto")); 46 StringAssert.IsMatch(@"^[a-f0-9]{16}_foo.protodep$", 47 DepFileUtil.GetDepFilenameForProto("", "foo.proto")); 48 } 49 50 [Test] GetDepFilenameForProto_HashesDir()51 public void GetDepFilenameForProto_HashesDir() 52 { 53 string PickHash(string fname) => 54 DepFileUtil.GetDepFilenameForProto("", fname).Substring(0, 16); 55 56 string same1 = PickHash("dir1/dir2/foo.proto"); 57 string same2 = PickHash("dir1/dir2/proto.foo"); 58 string same3 = PickHash("dir1/dir2/proto"); 59 string same4 = PickHash("dir1/dir2/.proto"); 60 string unsame1 = PickHash("dir2/foo.proto"); 61 string unsame2 = PickHash("/dir2/foo.proto"); 62 63 Assert.AreEqual(same1, same2); 64 Assert.AreEqual(same1, same3); 65 Assert.AreEqual(same1, same4); 66 Assert.AreNotEqual(same1, unsame1); 67 Assert.AreNotEqual(unsame1, unsame2); 68 } 69 70 [Test] GetOutputDirWithHash_IsSane()71 public void GetOutputDirWithHash_IsSane() 72 { 73 StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}$", 74 DepFileUtil.GetOutputDirWithHash("out", "foo.proto")); 75 StringAssert.IsMatch(@"^[a-f0-9]{16}$", 76 DepFileUtil.GetOutputDirWithHash("", "foo.proto")); 77 } 78 79 [Test] GetOutputDirWithHash_HashesDir()80 public void GetOutputDirWithHash_HashesDir() 81 { 82 string PickHash(string fname) => DepFileUtil.GetOutputDirWithHash("", fname); 83 84 string same1 = PickHash("dir1/dir2/foo.proto"); 85 string same2 = PickHash("dir1/dir2/proto.foo"); 86 string same3 = PickHash("dir1/dir2/proto"); 87 string same4 = PickHash("dir1/dir2/.proto"); 88 string unsame1 = PickHash("dir2/foo.proto"); 89 string unsame2 = PickHash("/dir2/foo.proto"); 90 91 Assert.AreEqual(same1, same2); 92 Assert.AreEqual(same1, same3); 93 Assert.AreEqual(same1, same4); 94 Assert.AreNotEqual(same1, unsame1); 95 Assert.AreNotEqual(unsame1, unsame2); 96 } 97 98 ////////////////////////////////////////////////////////////////////////// 99 // Full file reading tests 100 101 // Generated by protoc on Windows. Slashes vary. 102 const string depFile1 = 103 @"C:\projects\foo\src\./foo.grpc.pb.cc \ 104 C:\projects\foo\src\./foo.grpc.pb.h \ 105 C:\projects\foo\src\./foo.pb.cc \ 106 C:\projects\foo\src\./foo.pb.h: C:/usr/include/google/protobuf/wrappers.proto\ 107 C:/usr/include/google/protobuf/any.proto\ 108 C:/usr/include/google/protobuf/source_context.proto\ 109 C:/usr/include/google/protobuf/type.proto\ 110 foo.proto"; 111 112 // This has a nasty output directory with a space. 113 const string depFile2 = 114 @"obj\Release x64\net45\/Foo.cs \ 115 obj\Release x64\net45\/FooGrpc.cs: C:/usr/include/google/protobuf/wrappers.proto\ 116 C:/projects/foo/src//foo.proto"; 117 118 [Test] ReadDependencyInput_FullFile1()119 public void ReadDependencyInput_FullFile1() 120 { 121 string[] deps = ReadDependencyInputFromFileData(depFile1, "foo.proto"); 122 123 Assert.NotNull(deps); 124 Assert.That(deps, Has.Length.InRange(4, 5)); // foo.proto may or may not be listed. 125 Assert.That(deps, Has.One.EndsWith("wrappers.proto")); 126 Assert.That(deps, Has.One.EndsWith("type.proto")); 127 Assert.That(deps, Has.None.StartWith(" ")); 128 } 129 130 [Test] ReadDependencyInput_FullFile2()131 public void ReadDependencyInput_FullFile2() 132 { 133 string[] deps = ReadDependencyInputFromFileData(depFile2, "C:/projects/foo/src/foo.proto"); 134 135 Assert.NotNull(deps); 136 Assert.That(deps, Has.Length.InRange(1, 2)); 137 Assert.That(deps, Has.One.EndsWith("wrappers.proto")); 138 Assert.That(deps, Has.None.StartWith(" ")); 139 } 140 141 [Test] ReadDependencyInput_FullFileUnparsable()142 public void ReadDependencyInput_FullFileUnparsable() 143 { 144 string[] deps = ReadDependencyInputFromFileData("a:/foo.proto", "/foo.proto"); 145 Assert.NotNull(deps); 146 Assert.Zero(deps.Length); 147 } 148 ReadDependencyInputFromFileData(string fileData, string protoName)149 private string[] ReadDependencyInputFromFileData(string fileData, string protoName) 150 { 151 string randomTempDir = Path.GetTempPath() + '/' + Path.GetRandomFileName(); 152 Directory.CreateDirectory(randomTempDir); 153 string tempfile = DepFileUtil.GetDepFilenameForProto(randomTempDir, protoName); 154 try 155 { 156 File.WriteAllText(tempfile, fileData); 157 var mockEng = new Moq.Mock<IBuildEngine>(); 158 var log = new TaskLoggingHelper(mockEng.Object, "x"); 159 return DepFileUtil.ReadDependencyInputs(randomTempDir, protoName, log); 160 } 161 finally 162 { 163 try 164 { 165 File.Delete(tempfile); 166 } 167 catch { } 168 } 169 } 170 }; 171 } 172