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