Repository: mandiant/capa
File: tests/test_engine.py (Python)

Code before:
# Copyright (C) 2020 Mandiant, Inc. All Rights Reserved.
# 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: [package root]/LICENSE.txt
# 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.
import capa.features.address
from capa.engine import *
from capa.features import *
from capa.features.insn import *

ADDR1 = capa.features.address.AbsoluteVirtualAddress(0x401001)
ADDR2 = capa.features.address.AbsoluteVirtualAddress(0x401002)
ADDR3 = capa.features.address.AbsoluteVirtualAddress(0x401003)
ADDR4 = capa.features.address.AbsoluteVirtualAddress(0x401004)


def test_number():
    assert Number(1).evaluate({Number(0): {ADDR1}}) is False
    assert Number(1).evaluate({Number(1): {ADDR1}}) is True
    assert Number(1).evaluate({Number(2): {ADDR1, ADDR2}}) is False


def test_and():
    assert And([Number(1)]).evaluate({Number(0): {ADDR1}}) is False
    assert And([Number(1)]).evaluate({Number(1): {ADDR1}}) is True
    assert And([Number(1), Number(2)]).evaluate({Number(0): {ADDR1}}) is False
    assert And([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}}) is False
    assert And([Number(1), Number(2)]).evaluate({Number(2): {ADDR1}}) is False
    assert And([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}, Number(2): {ADDR2}}) is True


def test_or():
    assert Or([Number(1)]).evaluate({Number(0): {ADDR1}}) is False
    assert Or([Number(1)]).evaluate({Number(1): {ADDR1}}) is True
    assert Or([Number(1), Number(2)]).evaluate({Number(0): {ADDR1}}) is False
    assert Or([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}}) is True
    assert Or([Number(1), Number(2)]).evaluate({Number(2): {ADDR1}}) is True
    assert Or([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}, Number(2): {ADDR2}}) is True


def test_not():
    assert Not(Number(1)).evaluate({Number(0): {ADDR1}}) is True
    assert Not(Number(1)).evaluate({Number(1): {ADDR1}}) is False



Review comment (suggestion):
i think [evaluate](https://github.com/mandiant/capa/blob/8fe88f601f7d5c6fa775830c44f74147c68d4ba7/capa/engine.py#L56) returns a `Result` instance that implements [`__bool__`](https://github.com/mandiant/capa/blob/8fe88f601f7d5c6fa775830c44f74147c68d4ba7/capa/features/common.py#L96), which makes it easy to compare with True/False, like `if expr.evaluate(...): ...` but I'm not sure its correct to use `is`, because this compares specific object instances.

to make this more clear, perhaps we should update these tests to wrap the calls to `evaluate` with a cast to bool, like `bool(expr.evaluate(...)) is True`.

it was probably a mistake to implement `evaluate` and `Result` like this because the behavior is not obvious.

Code after:
# Copyright (C) 2020 Mandiant, Inc. All Rights Reserved.
# 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: [package root]/LICENSE.txt
# 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.
import capa.features.address
from capa.engine import *
from capa.features import *
from capa.features.insn import *

ADDR1 = capa.features.address.AbsoluteVirtualAddress(0x401001)
ADDR2 = capa.features.address.AbsoluteVirtualAddress(0x401002)
ADDR3 = capa.features.address.AbsoluteVirtualAddress(0x401003)
ADDR4 = capa.features.address.AbsoluteVirtualAddress(0x401004)


def test_number():
    assert bool(Number(1).evaluate({Number(0): {ADDR1}})) is False
    assert bool(Number(1).evaluate({Number(1): {ADDR1}})) is True
    assert bool(Number(1).evaluate({Number(2): {ADDR1, ADDR2}})) is False


def test_and():
    assert bool(And([Number(1)]).evaluate({Number(0): {ADDR1}})) is False
    assert bool(And([Number(1)]).evaluate({Number(1): {ADDR1}})) is True
    assert bool(And([Number(1), Number(2)]).evaluate({Number(0): {ADDR1}})) is False
    assert bool(And([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}})) is False
    assert bool(And([Number(1), Number(2)]).evaluate({Number(2): {ADDR1}})) is False
    assert bool(And([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}, Number(2): {ADDR2}})) is True


def test_or():
    assert bool(Or([Number(1)]).evaluate({Number(0): {ADDR1}})) is False
    assert bool(Or([Number(1)]).evaluate({Number(1): {ADDR1}})) is True
    assert bool(Or([Number(1), Number(2)]).evaluate({Number(0): {ADDR1}})) is False
    assert bool(Or([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}})) is True
    assert bool(Or([Number(1), Number(2)]).evaluate({Number(2): {ADDR1}})) is True
    assert bool(Or([Number(1), Number(2)]).evaluate({Number(1): {ADDR1}, Number(2): {ADDR2}})) is True


def test_not():
    assert bool(Not(Number(1)).evaluate({Number(0): {ADDR1}})) is True
    assert bool(Not(Number(1)).evaluate({Number(1): {ADDR1}})) is False