Command-line invocation of unittests from __main__

2019-06-07 14:32发布

问题:

I am solving some exercises in Python and using unittest to automate some of the verification of my code. One program runs the single unittest just fine and it passes. The second gives the following error:

$ python s1c6.py
E
======================================================================
ERROR: s1c6 (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute 's1c6'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

Here's the code for the working script:

# s1c5.py
import unittest

import cryptopals


class TestRepeatingKeyXor(unittest.TestCase):
    def testCase(self):
        key = b"ICE"
        data = b"Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"
        expected = bytes.fromhex(
            "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f")
        self.assertEqual(expected, cryptopals.xorcrypt(key, data))


if __name__ == "__main__":
    unittest.main()

And the code for the failing script:

# s1c6.py
import unittest
import bitstring

import cryptopals


class TestHammingDistance(unittest.TestCase):
    def testCase(self):
        str1 = b'this is a test'
        str2 = b'wokka wokka!!!'
        expected = 37
        self.assertEqual(expected, hamming_distance(str1, str2))


def hamming_distance(str1, str2):
    temp = cryptopals.xor(str1, str2)
    return sum(bitstring.Bits(temp))


if __name__ == "__main__":
    unittest.main()

I do not see a fundamental difference between these two programs that would cause an error in one and not the other. What am I missing?

import itertools
import operator


def xor(a, b):
    return bytes(map(operator.xor, a, b))


def xorcrypt(key, cipher):
    return b''.join(xor(key, x) for x in grouper(cipher, len(key)))


def grouper(iterable, n):
    it = iter(iterable)
    group = tuple(itertools.islice(it, n))
    while group:
        yield group
        group = tuple(itertools.islice(it, n))

"Raw" version of failing script:

# s1c6_raw.py
import cryptopals

key = b"ICE"
data = b"Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"
expected = bytes.fromhex(
    "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f")
print(cryptopals.xorcrypt(key, data))

The above runs fine and prints the expected output.

回答1:

The problem is that I was running the two scripts in different ways:

$ python s1c5.py

and

$ python s1c6.py s1c6.txt

Since unittest.main() parses command line arguments, there is an error in the second case. If I pass a command line argument to the first program, I also get the same error.