1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #include <utility> 17 18 #include "tensorflow/core/util/equal_graph_def.h" 19 20 #include "tensorflow/core/framework/node_def_util.h" 21 #include "tensorflow/core/framework/op.h" 22 #include "tensorflow/core/graph/graph_def_builder.h" 23 #include "tensorflow/core/kernels/ops_util.h" 24 #include "tensorflow/core/lib/core/status_test_util.h" 25 #include "tensorflow/core/platform/test.h" 26 #include "tensorflow/core/public/version.h" 27 28 namespace tensorflow { 29 namespace { 30 31 REGISTER_OP("Input").Output("o: float"); 32 REGISTER_OP("Alternate").Output("o: float"); 33 REGISTER_OP("Combine").Input("a: float").Input("b: float").Output("o: float"); 34 35 Node* Input(const GraphDefBuilder::Options& opts) { 36 return ops::SourceOp("Input", opts); 37 } 38 39 Node* Alternate(const GraphDefBuilder::Options& opts) { 40 return ops::SourceOp("Alternate", opts); 41 } 42 43 Node* Combine(ops::NodeOut a, ops::NodeOut b, 44 const GraphDefBuilder::Options& opts) { 45 return ops::BinaryOp("Combine", std::move(a), std::move(b), opts); 46 } 47 48 class EqualGraphDefTest : public ::testing::Test { 49 protected: 50 EqualGraphDefTest() 51 : e_(GraphDefBuilder::kFailImmediately), 52 a_(GraphDefBuilder::kFailImmediately) {} 53 54 bool Match() { 55 GraphDef expected; 56 TF_EXPECT_OK(e_.ToGraphDef(&expected)); 57 GraphDef actual; 58 TF_EXPECT_OK(a_.ToGraphDef(&actual)); 59 bool match = EqualGraphDef(actual, expected, &diff_); 60 if (match) { 61 EXPECT_EQ(GraphDefHash(expected), GraphDefHash(actual)); 62 } else { 63 // While, strictly speaking, this does not have to be the case, 64 // we want to check that our hash is more than "return 0;". 65 // If, in the extremely unlikely case, some different graphs 66 // legitimately produce equal hash values in this test, we can always 67 // tweak them a little to produce different hash values. 68 EXPECT_NE(GraphDefHash(expected), GraphDefHash(actual)); 69 } 70 return match; 71 } 72 73 GraphDefBuilder e_; 74 GraphDefBuilder a_; 75 string diff_; 76 }; 77 78 TEST_F(EqualGraphDefTest, Match) { 79 Input(e_.opts().WithName("A")); 80 Input(a_.opts().WithName("A")); 81 EXPECT_TRUE(Match()) << diff_; 82 } 83 84 TEST_F(EqualGraphDefTest, NoMatch) { 85 Input(e_.opts().WithName("A")); 86 Input(a_.opts().WithName("B")); 87 EXPECT_FALSE(Match()); 88 EXPECT_EQ("Did not find expected node 'A = Input[]()'", diff_); 89 } 90 91 TEST_F(EqualGraphDefTest, MissingNode) { 92 Input(e_.opts().WithName("A")); 93 Input(e_.opts().WithName("B")); 94 Input(a_.opts().WithName("A")); 95 EXPECT_FALSE(Match()); 96 EXPECT_EQ("Did not find expected node 'B = Input[]()'", diff_); 97 } 98 99 TEST_F(EqualGraphDefTest, ExtraNode) { 100 Input(e_.opts().WithName("A")); 101 Input(a_.opts().WithName("A")); 102 Input(a_.opts().WithName("B")); 103 EXPECT_FALSE(Match()); 104 EXPECT_EQ("Found unexpected node 'B = Input[]()'", diff_); 105 } 106 107 TEST_F(EqualGraphDefTest, NodeOrder) { 108 Node* a = Input(e_.opts().WithName("A")); 109 Node* b = Input(e_.opts().WithName("B")); 110 Combine(a, b, e_.opts().WithName("C")); 111 112 b = Input(a_.opts().WithName("B")); 113 a = Input(a_.opts().WithName("A")); 114 Combine(a, b, a_.opts().WithName("C")); 115 EXPECT_TRUE(Match()) << diff_; 116 } 117 118 TEST_F(EqualGraphDefTest, NameMismatch) { 119 Node* a = Input(e_.opts().WithName("A")); 120 Node* b = Input(e_.opts().WithName("B")); 121 // Have to call EqualNodeDef() directly here, since EqualGraphDef() 122 // only calls EqualNodeDef() with nodes that have matching names. 123 EXPECT_FALSE(EqualNodeDef(a->def(), b->def(), &diff_)); 124 EXPECT_EQ("Actual node name 'A' is not expected 'B'", diff_); 125 } 126 127 TEST_F(EqualGraphDefTest, OpMismatch) { 128 Input(e_.opts().WithName("A")); 129 Alternate(a_.opts().WithName("A")); 130 EXPECT_FALSE(Match()); 131 EXPECT_EQ("Node named 'A' has op 'Alternate' that is not expected 'Input'", 132 diff_); 133 } 134 135 TEST_F(EqualGraphDefTest, DeviceMatch) { 136 Input(e_.opts().WithName("A").WithDevice("/cpu:0")); 137 Input(a_.opts().WithName("A").WithDevice("/cpu:0")); 138 EXPECT_TRUE(Match()) << diff_; 139 } 140 141 TEST_F(EqualGraphDefTest, DeviceMismatch) { 142 Input(e_.opts().WithName("A").WithDevice("/cpu:0")); 143 Input(a_.opts().WithName("A").WithDevice("/cpu:1")); 144 EXPECT_FALSE(Match()); 145 EXPECT_EQ("Node named 'A' has device '/cpu:1' that is not expected '/cpu:0'", 146 diff_); 147 } 148 149 TEST_F(EqualGraphDefTest, InputMismatch) { 150 Node* a = Input(e_.opts().WithName("A")); 151 Node* b = Input(e_.opts().WithName("B")); 152 Combine(a, a, e_.opts().WithName("C")); 153 154 a = Input(a_.opts().WithName("A")); 155 b = Input(a_.opts().WithName("B")); 156 Combine(b, b, a_.opts().WithName("C")); 157 EXPECT_FALSE(Match()); 158 EXPECT_EQ("Node named 'C' has input 0 'B' that doesn't match expected 'A'", 159 diff_); 160 } 161 162 TEST_F(EqualGraphDefTest, InputOrderMismatch) { 163 Node* a = Input(e_.opts().WithName("A")); 164 Node* b = Input(e_.opts().WithName("B")); 165 Combine(a, b, e_.opts().WithName("C")); 166 167 a = Input(a_.opts().WithName("A")); 168 b = Input(a_.opts().WithName("B")); 169 Combine(b, a, a_.opts().WithName("C")); 170 EXPECT_FALSE(Match()); 171 EXPECT_EQ("Node named 'C' has input 0 'B' that doesn't match expected 'A'", 172 diff_); 173 } 174 175 TEST_F(EqualGraphDefTest, ControlInputOrder) { 176 Node* a = Input(e_.opts().WithName("A")); 177 Node* b = Input(e_.opts().WithName("B")); 178 Node* c = Input(e_.opts().WithName("C")); 179 Node* d = Input(e_.opts().WithName("D")); 180 Combine(a, a, 181 e_.opts() 182 .WithName("E") 183 .WithControlInput(b) 184 .WithControlInput(c) 185 .WithControlInput(d)); 186 187 a = Input(a_.opts().WithName("A")); 188 b = Input(a_.opts().WithName("B")); 189 c = Input(a_.opts().WithName("C")); 190 d = Input(a_.opts().WithName("D")); 191 Combine(a, a, 192 a_.opts() 193 .WithName("E") 194 .WithControlInput(c) 195 .WithControlInput(d) 196 .WithControlInput(b)); 197 EXPECT_TRUE(Match()) << diff_; 198 } 199 200 TEST_F(EqualGraphDefTest, ControlInputMismatch) { 201 Node* a = Input(e_.opts().WithName("A")); 202 Node* b = Input(e_.opts().WithName("B")); 203 Node* c = Input(e_.opts().WithName("C")); 204 Node* d = Input(e_.opts().WithName("D")); 205 Combine(a, a, 206 e_.opts().WithName("E").WithControlInput(b).WithControlInput(c)); 207 208 a = Input(a_.opts().WithName("A")); 209 b = Input(a_.opts().WithName("B")); 210 c = Input(a_.opts().WithName("C")); 211 d = Input(a_.opts().WithName("D")); 212 Combine(a, a, 213 a_.opts().WithName("E").WithControlInput(b).WithControlInput(d)); 214 EXPECT_FALSE(Match()); 215 EXPECT_EQ("Node named 'E' missing expected control input '^C'", diff_); 216 } 217 218 TEST_F(EqualGraphDefTest, ControlInputAdded) { 219 Node* a = Input(e_.opts().WithName("A")); 220 Node* b = Input(e_.opts().WithName("B")); 221 Node* c = Input(e_.opts().WithName("C")); 222 Combine(a, a, e_.opts().WithName("D").WithControlInput(b)); 223 224 a = Input(a_.opts().WithName("A")); 225 b = Input(a_.opts().WithName("B")); 226 c = Input(a_.opts().WithName("C")); 227 Combine(a, a, 228 a_.opts().WithName("D").WithControlInput(b).WithControlInput(c)); 229 EXPECT_FALSE(Match()); 230 EXPECT_EQ( 231 "Node named 'D' has inputs 'A, A, ^B, ^C' that don't match " 232 "expected 'A, A, ^B'", 233 diff_); 234 } 235 236 TEST_F(EqualGraphDefTest, ControlInputRemoved) { 237 Node* a = Input(e_.opts().WithName("A")); 238 Node* b = Input(e_.opts().WithName("B")); 239 Node* c = Input(e_.opts().WithName("C")); 240 Combine(a, a, 241 e_.opts().WithName("D").WithControlInput(b).WithControlInput(c)); 242 243 a = Input(a_.opts().WithName("A")); 244 b = Input(a_.opts().WithName("B")); 245 c = Input(a_.opts().WithName("C")); 246 Combine(a, a, a_.opts().WithName("D").WithControlInput(b)); 247 EXPECT_FALSE(Match()); 248 EXPECT_EQ( 249 "Node named 'D' has inputs 'A, A, ^B' that don't match " 250 "expected 'A, A, ^B, ^C'", 251 diff_); 252 } 253 254 TEST_F(EqualGraphDefTest, Attr) { 255 Node* a = Input(e_.opts().WithName("A")); 256 NodeDef same(a->def()); 257 AddNodeAttr("foo", "bar", &same); 258 EXPECT_TRUE(EqualNodeDef(same, same, &diff_)) << diff_; 259 } 260 261 TEST_F(EqualGraphDefTest, AttrAdded) { 262 Node* a = Input(e_.opts().WithName("A")); 263 NodeDef actual(a->def()); 264 AddNodeAttr("foo", "bar", &actual); 265 EXPECT_FALSE(EqualNodeDef(actual, a->def(), &diff_)); 266 EXPECT_EQ("Node named 'A' has unexpected attr 'foo' with value: \"bar\"", 267 diff_); 268 } 269 270 TEST_F(EqualGraphDefTest, AttrRemoved) { 271 Node* a = Input(e_.opts().WithName("A")); 272 NodeDef expected(a->def()); 273 AddNodeAttr("foo", "bar", &expected); 274 EXPECT_FALSE(EqualNodeDef(a->def(), expected, &diff_)); 275 EXPECT_EQ("Node named 'A' missing expected attr 'foo' with value: \"bar\"", 276 diff_); 277 } 278 279 TEST_F(EqualGraphDefTest, AttrOrder) { 280 Node* a = Input(e_.opts().WithName("A")); 281 NodeDef actual(a->def()); 282 AddNodeAttr("foo", "bar", &actual); 283 AddNodeAttr("baz", 42, &actual); 284 285 NodeDef expected(a->def()); 286 AddNodeAttr("baz", 42, &expected); 287 AddNodeAttr("foo", "bar", &expected); 288 289 EXPECT_TRUE(EqualNodeDef(actual, expected, &diff_)) << diff_; 290 } 291 292 TEST_F(EqualGraphDefTest, AttrMismatch) { 293 Node* a = Input(e_.opts().WithName("A")); 294 NodeDef actual(a->def()); 295 AddNodeAttr("foo", "bar", &actual); 296 AddNodeAttr("baz", 5, &actual); 297 298 NodeDef expected(a->def()); 299 AddNodeAttr("baz", 42, &expected); 300 AddNodeAttr("foo", "bar", &expected); 301 302 EXPECT_FALSE(EqualNodeDef(actual, expected, &diff_)); 303 EXPECT_EQ( 304 "Node named 'A' has attr 'baz' with value: 5 that does not match " 305 "expected: 42", 306 diff_); 307 } 308 309 TEST_F(EqualGraphDefTest, IgnoreInternalAttrs) { 310 Node* a = Input(e_.opts().WithName("A")); 311 NodeDef actual(a->def()); 312 AddNodeAttr("foo", "bar", &actual); 313 // Internal attrs are ignored. 314 AddNodeAttr("_class", 5, &actual); 315 316 NodeDef expected(a->def()); 317 AddNodeAttr("foo", "bar", &expected); 318 AddNodeAttr("_kernel", "eigen", &actual); 319 EXPECT_TRUE(EqualNodeDef(actual, expected, &diff_)); 320 } 321 322 } // namespace 323 } // namespace tensorflow 324