Home | History | Annotate | Download | only in util
      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