Skip to content

Commit

Permalink
Add a Testing library with a StrCheck class.
Browse files Browse the repository at this point in the history
The Testing library holds utility classes that are only used for unit testing.

The StrCheck class provides similar functionality to LLVM's FileCheck utility, but in a unit test context.
  • Loading branch information
Jakob Olesen authored and stoklund committed Dec 6, 2018
1 parent af851ab commit fd72c3a
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 0 deletions.
77 changes: 77 additions & 0 deletions include/glow/Testing/StrCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2018-present, Facebook, Inc.
*
* 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.
*/

#ifndef GLOW_TESTING_STRCHECK_H
#define GLOW_TESTING_STRCHECK_H

#include "llvm/ADT/StringRef.h"

#include <string>
#include <vector>

// Forward decls from googletest.
namespace testing {
class AssertionResult;
}

namespace glow {

/// Helper class for finding ordered substrings in a larger string.
///
/// The StrCheck class is intended to be used in googletest unit tests:
///
/// EXPECT_TRUE(StrCheck(asm).check("foo").no("baz").sameln("arg=7"));
///
/// A typical use is to search for expected instruction patterns in
/// disassembled code generated for a test case.
class StrCheck {
public:
StrCheck(llvm::StringRef input) : input_(input) {}

/// Check that `needle` appears in the input at a point after the previous
/// match.
StrCheck &check(llvm::StringRef needle);

/// Check that `needle` appears on the same line as the previous match. (And
/// following the previous match).
StrCheck &sameln(llvm::StringRef needle);

/// Check that `needle` appears on the next line after the previous match.
StrCheck &nextln(llvm::StringRef needle);

/// Check that no instances of `needle` appear before the next positive match.
StrCheck &no(llvm::StringRef needle);

private:
const std::string input_;
size_t pos_ = 0;
std::string errors_;
std::vector<std::string> nos_;

size_t findEol(size_t p) const;
size_t findEol() const;
StrCheck &match(size_t pos, size_t size);
StrCheck &fail(const char *msg, llvm::StringRef needle);

public:
// Allow implicit conversion to allow a StrCheck to be used in EXPECT_TRUE().
operator testing::AssertionResult();
operator bool();
};

} // namespace glow

#endif // GLOW_TESTING_STRCHECK_H
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ add_subdirectory(Importer)
add_subdirectory(Optimizer)
add_subdirectory(Quantization)
add_subdirectory(Support)
add_subdirectory(Testing)
add_subdirectory(Onnxifi)
5 changes: 5 additions & 0 deletions lib/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_library(Testing
StrCheck.cpp)
target_link_libraries(Testing
PRIVATE
gtest)
90 changes: 90 additions & 0 deletions lib/Testing/StrCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2018-present, Facebook, Inc.
*
* 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.
*/

#include "glow/Testing/StrCheck.h"
#include "gtest/gtest.h"

using glow::StrCheck;

StrCheck &StrCheck::check(llvm::StringRef needle) {
size_t found = input_.find(needle, pos_);
return found != std::string::npos ? match(found, needle.size())
: fail("not found: check", needle);
}

StrCheck &StrCheck::sameln(llvm::StringRef needle) {
size_t found = input_.find(needle, pos_);
return found < findEol() ? match(found, needle.size())
: fail("not found: sameln", needle);
}

StrCheck &StrCheck::nextln(llvm::StringRef needle) {
size_t eol = findEol();
size_t found = input_.find(needle, eol);
return found < findEol(eol) ? match(found, needle.size())
: fail("not found: nextln", needle);
}

StrCheck &StrCheck::no(llvm::StringRef needle) {
nos_.push_back(needle);
return *this;
}

StrCheck &StrCheck::match(size_t at, size_t size) {
// We have a positive match. Check if any of the no()'s appeared between
// `pos_` and `at`.
for (const auto &no : nos_) {
if (pos_ + no.size() > at)
continue;
if (input_.find(no, pos_) <= at - no.size())
fail("matched not", no);
}
nos_.clear();

pos_ = at + size;
return *this;
}

StrCheck &StrCheck::fail(const char *msg, llvm::StringRef needle) {
errors_ += ">>> ";
errors_ += msg;
errors_ += "(\"";
errors_ += needle;
errors_ += "\")\n";
return *this;
}

size_t StrCheck::findEol(size_t p) const {
size_t eol = input_.find('\n', p);
return eol == std::string::npos ? input_.size() : eol + 1;
}

size_t StrCheck::findEol() const { return findEol(pos_); }

StrCheck::operator testing::AssertionResult() {
if (*this)
return testing::AssertionSuccess();
else
return testing::AssertionFailure() << "Failed StrCheck in:\n"
<< input_ << '\n'
<< errors_;
}

StrCheck::operator bool() {
// Match up to the end of the input to make sure we catch any trailing no()'s.
match(input_.size(), 0);
return errors_.empty();
}
2 changes: 2 additions & 0 deletions tests/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ add_glow_test(typeAToTypeBFunctionConverterTest
${GLOW_BINARY_DIR}/tests/typeAToTypeBFunctionConverterTest --gtest_output=xml:typeAToTypeBFunctionConverterTest.xml)

add_executable(UtilsTest
StrCheck.cpp
UtilsTest.cpp)
target_link_libraries(UtilsTest
PRIVATE
Base
Support
Testing
gtest
testMain)
add_glow_test(UtilsTest ${GLOW_BINARY_DIR}/tests/UtilsTest --gtest_output=xml:UtilsTest.xml)
Expand Down
46 changes: 46 additions & 0 deletions tests/unittests/StrCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2018-present, Facebook, Inc.
*
* 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.
*/

#include "glow/Testing/StrCheck.h"
#include "gtest/gtest.h"

using glow::StrCheck;

TEST(StrCheck, check) {
EXPECT_TRUE(StrCheck("foo bar").check("oo").check("bar"));
EXPECT_FALSE(StrCheck("foo bar").check("foo").check("oo"));
}

TEST(StrCheck, sameln) {
EXPECT_TRUE(StrCheck("foo bar").sameln("foo").sameln("bar"));
EXPECT_FALSE(StrCheck("foo\nbar").sameln("foo").sameln("bar"));
}

TEST(StrCheck, nextln) {
EXPECT_FALSE(StrCheck("foo bar").check("foo").nextln("bar"));
EXPECT_TRUE(StrCheck("foo\nbar").check("foo").nextln("bar"));
EXPECT_FALSE(StrCheck("foo\n\nbar").check("foo").nextln("bar"));
}

TEST(StrCheck, no) {
EXPECT_TRUE(StrCheck("foo bar").check("foo").no("baz"));
EXPECT_FALSE(StrCheck("foo bar").check("foo").no("bar"));
EXPECT_TRUE(StrCheck("foo bar").no("baz").check("bar"));
EXPECT_FALSE(StrCheck("foo bar").no("foo").check("bar"));
EXPECT_TRUE(StrCheck("foo bar").check("foo").no("o"));

EXPECT_FALSE(StrCheck("foo bar\nbaz").check("foo").no("bar").nextln("baz"));
}

0 comments on commit fd72c3a

Please sign in to comment.