<commit_before>#include <gtest/gtest.h>
#include <errors.h>
#include <basecpu.h>
#include "dummy_instruction.h"
#include "mock_instruction.h"
#include "mock_system.h"

#define BASECPU_TEST_CLASS BaseCPUTest
#define GENERICCPU_TEST_CLASS GenericCPUTest

#define GENERICCPU_BAD_OPERAND_INT 1
#define GENERICCPU_BAD_INSTRUCTION_INT 2

class BaseTestCPU : public BaseCPU {
public:
    BaseTestCPU(int maxTicks, const System &sys) :
        maxTicks(maxTicks), resets(0), startups(0), ticks(0), BaseCPU(sys) { }

    virtual bool startup() {
        startups++;
        return BaseCPU::startup();
    }

    void reset() {
        resets++;
    }

    void tick() {
        assert(isRunning());
        ticks++;
        if(ticks>= maxTicks) {
            stop();
        }
    }

    int doReadMemory(SizeType offset, SizeType len, void *data) const {
        return BaseCPU::readMemory(offset, len, data);
    }

    int doWriteMemory(SizeType offset, SizeType len, const void *data) const {
        return BaseCPU::writeMemory(offset, len, data);
    }

    int doReadPort(PortType port, SizeType len, void *data) const {
        return BaseCPU::readPort(port, len, data);
    }

    int doWritePort(PortType port, SizeType len, const void *data) const {
        return BaseCPU::writePort(port, len, data);
    }

    int maxTicks;
    int resets;
    int startups;
    int ticks;
};

class TestInterruptable : public Interruptable {
public:
    virtual void serviceInterrupt(Interrupt interrupt) {
        servicedInterrupts.push_back(interrupt);
    }

    bool _nextI() { return serviceNextInterrupt(); }

    std::vector<Interrupt> servicedInterrupts;
};

class GenericTestCPU : public GenericCPU, public TestInterruptable {
public:
    GenericTestCPU(const System &sys, const InstructionSet &set) :
        GenericCPU(sys, set, GENERICCPU_BAD_INSTRUCTION_INT, GENERICCPU_BAD_OPERAND_INT),
        ip(nullptr), interruptable(true), resets(0) { }

    void *instructionPointer() { return ip; }
    bool interruptsEnabled() { return interruptable; }

    void reset() {
        resets++;
    }

    SizeType interruptQueueLength() {
        return GenericCPU::interruptQueueLength();
    }

    bool serviceNextInterrupt() {
        return GenericCPU::serviceNextInterrupt();
    }

    void serviceInterrupt(Interrupt interrupt) {
        TestInterruptable::serviceInterrupt(interrupt);
    }

    bool readNextByte(ByteString &buffer, const void * const base) {
        return GenericCPU::readNextByte(buffer, base);
    }

    int readInstruction(const void * const instructionBase, const Instruction **out) {
        return GenericCPU::readInstruction(instructionBase, out);
    }

    void loadNextInstruction(const Instruction **instruction, ByteString &operands) {
        return GenericCPU::loadNextInstruction(instruction, operands);
    }

    void *ip;
    bool interruptable;
    int resets;
};

int buildDummyInstruction(const ByteString &opcode, const Instruction **out) {
    // FIXME: Memory leak
    *out = new DummyInstruction(opcode, 2);
    return ERR_SUCCESS;
}

const int TEST_TICK_COUNT = 3;

class BASECPU_TEST_CLASS : public testing::Test {
protected:
    BASECPU_TEST_CLASS() : cpu(TEST_TICK_COUNT, dummySystem) { }
    BaseTestCPU cpu;
    TestInterruptable server;
    StrictMockSystem dummySystem;
};

TEST_F(BASECPU_TEST_CLASS, TestRunLoop) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";
}

TEST_F(BASECPU_TEST_CLASS, TestStopStart) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";

    started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT + 1) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 2) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 2) << "Incorrect final CPU startup count";
}

TEST_F(BASECPU_TEST_CLASS, TestInterruptService) {
    ASSERT_FALSE(server._nextI()) << "Incorrect service of empty queue";
    server.signalInterrupt(3);
    server.signalInterrupt(5);
    ASSERT_TRUE(server._nextI()) << "Failed to service queue";
    ASSERT_EQ(server.servicedInterrupts.size(), 1) << "Incorrect number of interrupts serviced";
    ASSERT_EQ(server.servicedInterrupts.at(0), 3) << "Incorrect interrupt serviced";
    ASSERT_TRUE(server._nextI()) << "Failed to service queue";
    ASSERT_EQ(server.servicedInterrupts.size(), 2) << "Incorrect number of interrupts serviced";
    ASSERT_EQ(server.servicedInterrupts.at(1), 5) << "Incorrect interrupt serviced";
    ASSERT_FALSE(server._nextI()) << "Incorrect service of empty queue";
}

TEST_F(BASECPU_TEST_CLASS, TestSystemPassThru) {
    // These constants aren't important.  I just wanted to make sure calls aren't crossed
    EXPECT_CALL(dummySystem, readMemory(1, 2, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, writeMemory(7, 8, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, readPort(5, 6, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, writePort(3, 4, 0)).WillOnce(testing::Return(ERR_SUCCESS));

    cpu.doReadMemory(1, 2, 0);
    cpu.doWriteMemory(7, 8, 0);
    cpu.doReadPort(5, 6, 0);
    cpu.doWritePort(3, 4, 0);
}

TEST_F(BASECPU_TEST_CLASS, TestReadInstruction) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";
}

class GENERICCPU_TEST_CLASS : public testing::Test {
protected:
    GENERICCPU_TEST_CLASS() : cpu(dummySystem, dummySet) { }
    GenericTestCPU cpu;
    StrictMockSystem dummySystem;
    StrictMockInstructionSet dummySet;
};

TEST_F(GENERICCPU_TEST_CLASS, readNextByteSuccess) {
    ByteString buffer;
    const void * const baseAddr = (void*)0x1234;
    SizeType bytesToRead = 8;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(bytesToRead).WillRepeatedly(testing::Return(ERR_SUCCESS));

    while(bytesToRead-- && cpu.readNextByte(buffer, baseAddr)) { }
}

TEST_F(GENERICCPU_TEST_CLASS, readNextByteFailure) {
    ByteString buffer;
    const void * const baseAddr = (void*)0x1234;
    SizeType bytesToRead = 8;
    SizeType bytesToSucceed = 5;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_BADRANGE))
        .RetiresOnSaturation();
    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(bytesToSucceed).WillRepeatedly(testing::Return(ERR_SUCCESS))
        .RetiresOnSaturation();

    while(bytesToRead-- && cpu.readNextByte(buffer, baseAddr)) { }
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionSuccess) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_SUCCESS));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_SUCCESS) << "Failed to decode instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionMemoryError) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_BADRANGE));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_CONFLICT) << "Failed to detect memory failure";
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionInstructionError) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(2).WillRepeatedly(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_BADRANGE));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_BADRANGE) << "Failed to detect invalid instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionSuccess) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce((testing::Invoke(buildDummyInstruction)));

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 2, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS));

    cpu.loadNextInstruction(&instr, operands);

    ASSERT_EQ(cpu.interruptQueueLength(), 0) << "CPU fault loading instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionMemoryError) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_BADRANGE));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE));

    cpu.loadNextInstruction(&instr, operands);
    ASSERT_EQ(cpu.interruptQueueLength(), 1) << "Memory error did not trigger CPU fault";
    cpu.serviceNextInterrupt();
    ASSERT_EQ(*cpu.servicedInterrupts.begin(), GENERICCPU_BAD_OPERAND_INT)
        << "Incorrect interrupt trigger by memory fault";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionInstructionError) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(2).WillRepeatedly(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_BADRANGE));

    cpu.loadNextInstruction(&instr, operands);
    ASSERT_EQ(cpu.interruptQueueLength(), 1) << "Invalid instruction did not trigger CPU fault";
    cpu.serviceNextInterrupt();
    ASSERT_EQ(*cpu.servicedInterrupts.begin(), GENERICCPU_BAD_INSTRUCTION_INT)
        << "Incorrect interrupt trigger by invalid instruction";
}
<commit_msg>Fix bad test name<commit_after>#include <gtest/gtest.h>
#include <errors.h>
#include <basecpu.h>
#include "dummy_instruction.h"
#include "mock_instruction.h"
#include "mock_system.h"

#define BASECPU_TEST_CLASS BaseCPUTest
#define GENERICCPU_TEST_CLASS GenericCPUTest

#define GENERICCPU_BAD_OPERAND_INT 1
#define GENERICCPU_BAD_INSTRUCTION_INT 2

class BaseTestCPU : public BaseCPU {
public:
    BaseTestCPU(int maxTicks, const System &sys) :
        maxTicks(maxTicks), resets(0), startups(0), ticks(0), BaseCPU(sys) { }

    virtual bool startup() {
        startups++;
        return BaseCPU::startup();
    }

    void reset() {
        resets++;
    }

    void tick() {
        assert(isRunning());
        ticks++;
        if(ticks>= maxTicks) {
            stop();
        }
    }

    int doReadMemory(SizeType offset, SizeType len, void *data) const {
        return BaseCPU::readMemory(offset, len, data);
    }

    int doWriteMemory(SizeType offset, SizeType len, const void *data) const {
        return BaseCPU::writeMemory(offset, len, data);
    }

    int doReadPort(PortType port, SizeType len, void *data) const {
        return BaseCPU::readPort(port, len, data);
    }

    int doWritePort(PortType port, SizeType len, const void *data) const {
        return BaseCPU::writePort(port, len, data);
    }

    int maxTicks;
    int resets;
    int startups;
    int ticks;
};

class TestInterruptable : public Interruptable {
public:
    virtual void serviceInterrupt(Interrupt interrupt) {
        servicedInterrupts.push_back(interrupt);
    }

    bool _nextI() { return serviceNextInterrupt(); }

    std::vector<Interrupt> servicedInterrupts;
};

class GenericTestCPU : public GenericCPU, public TestInterruptable {
public:
    GenericTestCPU(const System &sys, const InstructionSet &set) :
        GenericCPU(sys, set, GENERICCPU_BAD_INSTRUCTION_INT, GENERICCPU_BAD_OPERAND_INT),
        ip(nullptr), interruptable(true), resets(0) { }

    void *instructionPointer() { return ip; }
    bool interruptsEnabled() { return interruptable; }

    void reset() {
        resets++;
    }

    SizeType interruptQueueLength() {
        return GenericCPU::interruptQueueLength();
    }

    bool serviceNextInterrupt() {
        return GenericCPU::serviceNextInterrupt();
    }

    void serviceInterrupt(Interrupt interrupt) {
        TestInterruptable::serviceInterrupt(interrupt);
    }

    bool readNextByte(ByteString &buffer, const void * const base) {
        return GenericCPU::readNextByte(buffer, base);
    }

    int readInstruction(const void * const instructionBase, const Instruction **out) {
        return GenericCPU::readInstruction(instructionBase, out);
    }

    void loadNextInstruction(const Instruction **instruction, ByteString &operands) {
        return GenericCPU::loadNextInstruction(instruction, operands);
    }

    void *ip;
    bool interruptable;
    int resets;
};

int buildDummyInstruction(const ByteString &opcode, const Instruction **out) {
    // FIXME: Memory leak
    *out = new DummyInstruction(opcode, 2);
    return ERR_SUCCESS;
}

const int TEST_TICK_COUNT = 3;

class BASECPU_TEST_CLASS : public testing::Test {
protected:
    BASECPU_TEST_CLASS() : cpu(TEST_TICK_COUNT, dummySystem) { }
    BaseTestCPU cpu;
    TestInterruptable server;
    StrictMockSystem dummySystem;
};

TEST_F(BASECPU_TEST_CLASS, TestRunLoop) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";
}

TEST_F(BASECPU_TEST_CLASS, TestStopStart) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";

    started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT + 1) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 2) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 2) << "Incorrect final CPU startup count";
}

TEST_F(BASECPU_TEST_CLASS, TestInterruptService) {
    ASSERT_FALSE(server._nextI()) << "Incorrect service of empty queue";
    server.signalInterrupt(3);
    server.signalInterrupt(5);
    ASSERT_TRUE(server._nextI()) << "Failed to service queue";
    ASSERT_EQ(server.servicedInterrupts.size(), 1) << "Incorrect number of interrupts serviced";
    ASSERT_EQ(server.servicedInterrupts.at(0), 3) << "Incorrect interrupt serviced";
    ASSERT_TRUE(server._nextI()) << "Failed to service queue";
    ASSERT_EQ(server.servicedInterrupts.size(), 2) << "Incorrect number of interrupts serviced";
    ASSERT_EQ(server.servicedInterrupts.at(1), 5) << "Incorrect interrupt serviced";
    ASSERT_FALSE(server._nextI()) << "Incorrect service of empty queue";
}

TEST_F(BASECPU_TEST_CLASS, TestSystemPassThru) {
    // These constants aren't important.  I just wanted to make sure calls aren't crossed
    EXPECT_CALL(dummySystem, readMemory(1, 2, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, writeMemory(7, 8, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, readPort(5, 6, 0)).WillOnce(testing::Return(ERR_SUCCESS));
    EXPECT_CALL(dummySystem, writePort(3, 4, 0)).WillOnce(testing::Return(ERR_SUCCESS));

    cpu.doReadMemory(1, 2, 0);
    cpu.doWriteMemory(7, 8, 0);
    cpu.doReadPort(5, 6, 0);
    cpu.doWritePort(3, 4, 0);
}

TEST_F(BASECPU_TEST_CLASS, TestStartup) {
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect initial CPU running state";
    ASSERT_EQ(cpu.ticks, 0) << "Incorrect initial CPU tick count";
    ASSERT_EQ(cpu.resets, 0) << "Incorrect initial CPU reset count";
    bool started = cpu.startup();
    ASSERT_TRUE(started) << "CPU failed to indicate startup";
    ASSERT_FALSE(cpu.isRunning()) << "Incorrect final CPU running state";
    ASSERT_EQ(cpu.ticks, TEST_TICK_COUNT) << "Incorrect final CPU tick count";
    ASSERT_EQ(cpu.resets, 1) << "Incorrect final CPU reset count";
    ASSERT_EQ(cpu.startups, 1) << "Incorrect final CPU startup count";
}

class GENERICCPU_TEST_CLASS : public testing::Test {
protected:
    GENERICCPU_TEST_CLASS() : cpu(dummySystem, dummySet) { }
    GenericTestCPU cpu;
    StrictMockSystem dummySystem;
    StrictMockInstructionSet dummySet;
};

TEST_F(GENERICCPU_TEST_CLASS, readNextByteSuccess) {
    ByteString buffer;
    const void * const baseAddr = (void*)0x1234;
    SizeType bytesToRead = 8;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(bytesToRead).WillRepeatedly(testing::Return(ERR_SUCCESS));

    while(bytesToRead-- && cpu.readNextByte(buffer, baseAddr)) { }
}

TEST_F(GENERICCPU_TEST_CLASS, readNextByteFailure) {
    ByteString buffer;
    const void * const baseAddr = (void*)0x1234;
    SizeType bytesToRead = 8;
    SizeType bytesToSucceed = 5;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_BADRANGE))
        .RetiresOnSaturation();
    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(bytesToSucceed).WillRepeatedly(testing::Return(ERR_SUCCESS))
        .RetiresOnSaturation();

    while(bytesToRead-- && cpu.readNextByte(buffer, baseAddr)) { }
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionSuccess) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_SUCCESS));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_SUCCESS) << "Failed to decode instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionMemoryError) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_BADRANGE));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_CONFLICT) << "Failed to detect memory failure";
}

TEST_F(GENERICCPU_TEST_CLASS, readInstructionInstructionError) {
    const void * const baseAddr = (void*)0x1234;
    const Instruction *instr;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(2).WillRepeatedly(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_BADRANGE));

    int instructionRc = cpu.readInstruction(baseAddr, &instr);
    ASSERT_EQ(instructionRc, ERR_BADRANGE) << "Failed to detect invalid instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionSuccess) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce((testing::Invoke(buildDummyInstruction)));

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 2, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS));

    cpu.loadNextInstruction(&instr, operands);

    ASSERT_EQ(cpu.interruptQueueLength(), 0) << "CPU fault loading instruction";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionMemoryError) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .WillOnce(testing::Return(ERR_SUCCESS)).WillOnce(testing::Return(ERR_BADRANGE));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE));

    cpu.loadNextInstruction(&instr, operands);
    ASSERT_EQ(cpu.interruptQueueLength(), 1) << "Memory error did not trigger CPU fault";
    cpu.serviceNextInterrupt();
    ASSERT_EQ(*cpu.servicedInterrupts.begin(), GENERICCPU_BAD_OPERAND_INT)
        << "Incorrect interrupt trigger by memory fault";
}

TEST_F(GENERICCPU_TEST_CLASS, loadNextInstructionInstructionError) {
    const Instruction *instr;
    ByteString operands;

    EXPECT_CALL(dummySystem, readMemory(::testing::_, 1, ::testing::_))
        .Times(2).WillRepeatedly(testing::Return(ERR_SUCCESS));

    EXPECT_CALL(dummySet, decode(::testing::_, &instr))
        .WillOnce(testing::Return(ERR_INCOMPLETE)).WillOnce(testing::Return(ERR_BADRANGE));

    cpu.loadNextInstruction(&instr, operands);
    ASSERT_EQ(cpu.interruptQueueLength(), 1) << "Invalid instruction did not trigger CPU fault";
    cpu.serviceNextInterrupt();
    ASSERT_EQ(*cpu.servicedInterrupts.begin(), GENERICCPU_BAD_INSTRUCTION_INT)
        << "Incorrect interrupt trigger by invalid instruction";
}
<|endoftext|>


<commit_before>/******************************************************************************

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, Jeffrey Carpenter <jeffrey.carp@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

******************************************************************************/
#include "nomlib/graphics/Image.hpp"

namespace nom {

Image::Image ( void ) : image_ ( nullptr, priv::FreeSurface )
{
NOM_LOG_TRACE ( NOM );

  if ( IMG_Init ( IMG_INIT_PNG ) != IMG_INIT_PNG )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
  }

  atexit ( IMG_Quit );
}

Image::~Image ( void )
{
NOM_LOG_TRACE ( NOM );
}

Image::Image ( uint32 flags ) : image_ ( nullptr, priv::FreeSurface )
{
NOM_LOG_TRACE ( NOM );

  if ( IMG_Init ( flags ) != flags )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
  }

  atexit ( IMG_Quit );
}

Image::Image ( const Image& other )  : image_ { other.image(), priv::FreeSurface }
{
NOM_LOG_TRACE ( NOM );
}

Image& Image::operator = ( const Image& other )
{
  this->image_ = other.image_;

  return *this;
}

bool Image::initialize( void* pixels, int32 width, int32 height,
                        int32 bits_per_pixel, uint16 pitch,
                        uint32 Rmask, uint32 Gmask, uint32 Bmask, uint32 Amask
                      )
{
NOM_LOG_TRACE ( NOM );

  this->image_.reset ( SDL_CreateRGBSurfaceFrom ( pixels, width, height, bits_per_pixel, pitch, Rmask, Gmask, Bmask, Amask ), priv::FreeSurface );
  //this->set_bounds ( Coords ( 0, 0, width, height ) );

  if ( this->valid() == false )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::initialize ( int32 width, int32 height, uint8 bits_per_pixel, uint32 Rmask, uint32 Gmask, uint32 Bmask, uint32 Amask, bool colorkey )
{
NOM_LOG_TRACE ( NOM );

  this->image_.reset ( SDL_CreateRGBSurface ( 0, width, height, bits_per_pixel, Rmask, Gmask, Bmask, Amask ), priv::FreeSurface );
  //this->set_bounds ( Coords ( 0, 0, width, height ) );

  if ( this->valid() == false )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  // If the video surface is marked for color keying transparency, we need to
  // set it up here and now!
  if ( colorkey )
  {
    if ( this->set_colorkey ( this->colorkey(), true ) == false )
    {
      NOM_LOG_ERR ( NOM, "Could not create the video surface with color key transparency." );
      return false;
    }
  }

  return true;
}

SDL_SURFACE::RawPtr Image::image ( void ) const
{
  return this->image_.get();
}

bool Image::valid ( void ) const
{
  if ( this->image() != nullptr ) return true;

  return false;
}

int32 Image::width ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->w;
}

int32 Image::height ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->h;
}

void* Image::pixels ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->pixels;
}

uint16 Image::pitch ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->pitch;
}

uint8 Image::bits_per_pixel ( void ) const
{
  SDL_Surface* buffer = this->image();

  return buffer->format->BitsPerPixel;
}

const SDL_PIXELFORMAT::RawPtr Image::pixel_format ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->format;
}

const uint32 Image::red_mask ( void ) const
{
  return this->pixel_format()->Rmask;
}

const uint32 Image::green_mask ( void ) const
{
  return this->pixel_format()->Gmask;
}

const uint32 Image::blue_mask ( void ) const
{
  return this->pixel_format()->Bmask;
}

const uint32 Image::alpha_mask ( void ) const
{
  return this->pixel_format()->Amask;
}

const Coords Image::bounds ( void ) const
{
  SDL_Rect clip_buffer; // temporary storage struct
  Coords clip_bounds; // transferred values from SDL_Rect clip_buffer

  // Return values are put into the clip_buffer SDL_Rect after executing:
  SDL_GetClipRect ( this->image(), &clip_buffer );

  // Now transfer the values into our preferred data container type
  clip_bounds = Coords ( clip_buffer.x, clip_buffer.y, clip_buffer.w, clip_buffer.h );

  return clip_bounds;
}

bool Image::must_lock ( void ) const
{
  if ( SDL_MUSTLOCK ( this->image() ) ) return true;

  return false;
}

bool Image::locked ( void ) const
{
  return this->image()->locked;
}

const uint8 Image::alpha ( void ) const
{
  uint8 alpha;

  if ( SDL_GetSurfaceAlphaMod ( this->image(), &alpha ) != 0 )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return 0;
  }

  return alpha;
}

void Image::set_bounds ( const Coords& clip_bounds )
{
  SDL_Rect clip = SDL_RECT ( clip_bounds );

  // As per libSDL docs, if SDL_Rect is nullptr, the clipping rectangle is set
  // to the full size of the surface
  SDL_SetClipRect ( this->image(), &clip );
}

bool Image::load ( const std::string& filename )
{
  SDL_Surface *buffer = IMG_Load ( filename.c_str() );

  if ( buffer == nullptr )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  this->image_.reset ( SDL_ConvertSurfaceFormat ( buffer, SDL_PIXELFORMAT_ARGB8888, 0 ), priv::FreeSurface );
  priv::FreeSurface ( buffer );

  return true;
}

bool Image::load_bmp ( const std::string& filename )
{
  SDL_Surface *buffer = IMG_Load ( filename.c_str() );
  if ( buffer == nullptr )
  {
    NOM_LOG_ERR ( NOM, IMG_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  this->image_.reset ( SDL_ConvertSurfaceFormat ( buffer, SDL_PIXELFORMAT_ARGB8888, 0 ), priv::FreeSurface );
  priv::FreeSurface ( buffer );

  return true;
}

bool Image::save ( const std::string& filename, SDL_SURFACE::RawPtr video_buffer ) const
{
  if ( SDL_SaveBMP ( video_buffer, filename.c_str() ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::save ( const std::string& filename ) const
{
  if ( this->save( filename, this->image() ) == false ) return false;

  // Success!
  return true;
}

bool Image::save_png ( const std::string& filename ) const
{
  // Undocumented method for writing out a PNG file with SDL2_image
  if ( IMG_SavePNG ( this->image(), filename.c_str() ) != 0 )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

const Point2i Image::size ( void ) const
{
  SDL_Surface* buffer = this->image();
  Point2i image_pos ( buffer->w, buffer->h );

  return image_pos;
}

const Color4u Image::colorkey ( void ) const
{
  SDL_Surface* buffer = this->image();
  uint32 transparent_color = 0;
  Color4u key;

  if ( SDL_GetColorKey ( this->image(), &transparent_color ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    priv::FreeSurface ( buffer );
    return NOM_COLOR4U_BLACK;
  }

  return nom::pixel ( transparent_color, buffer->format ); // SDL_helper function
}

const SDL_BlendMode Image::blend_mode ( void ) const
{
  SDL_BlendMode blend;

  if ( SDL_GetSurfaceBlendMode ( this->image(), &blend ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return blend;
  }

  return blend;
}

bool Image::set_colorkey ( const Color4u& colorkey, bool flag )
{
  SDL_Surface* buffer = this->image();
  uint32 transparent_color = RGB ( colorkey, buffer->format );

  if ( this->valid() == false )
  {
NOM_LOG_ERR ( NOM, "Could not set color key: invalid image buffer." );
    priv::FreeSurface ( buffer );
    return false;
  }

  if ( SDL_SetColorKey ( buffer, SDL_BOOL(flag), transparent_color ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  return true;
}

bool Image::RLE ( bool flag )
{
  if ( SDL_SetSurfaceRLE ( this->image(), SDL_BOOL(flag) ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }
  return true;
}

uint32 Image::pixel ( int32 x, int32 y )
{
  switch ( this->bits_per_pixel() )
  {
    default: return -1; break; // Unknown

    case 8:
    {
      uint8* pixels = static_cast<uint8*> ( this->pixels() );

      return pixels[ ( y * this->pitch() ) + x ];
    }
    break;

    case 16:
    {
      uint16* pixels = static_cast<uint16*> ( this->pixels() );

      return pixels[ ( y * this->pitch() / 2 ) + x ];
    }
    break;

    case 24:
    {
      uint8* pixels = static_cast<uint8*> ( this->pixels() );

      return pixels[ ( y * this->pitch() ) + x ];
    }
    break;

    case 32:
    {
      uint32* pixels = static_cast<uint32*> ( this->pixels() );

      return pixels[ ( y * this->pitch()/4 ) + x ];
    }
    break;
  } // end switch
}

bool Image::set_blend_mode ( const SDL_BlendMode blend )
{
  if ( SDL_SetSurfaceBlendMode ( this->image(), blend ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::lock ( void ) const
{
  if ( SDL_BOOL ( this->must_lock() ) )
  {
    if ( SDL_LockSurface ( this->image() ) != 0 )
    {
NOM_LOG_ERR ( NOM, "Could not lock video surface memory." );
      return false;
    }
  }

  return true;
}

void Image::unlock ( void ) const
{
  SDL_UnlockSurface ( this->image() );
}

} // namespace nom
<commit_msg>Image: Fix crash due to improper pointer release<commit_after>/******************************************************************************

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, Jeffrey Carpenter <jeffrey.carp@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

******************************************************************************/
#include "nomlib/graphics/Image.hpp"

namespace nom {

Image::Image ( void ) : image_ ( nullptr, priv::FreeSurface )
{
NOM_LOG_TRACE ( NOM );

  if ( IMG_Init ( IMG_INIT_PNG ) != IMG_INIT_PNG )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
  }

  atexit ( IMG_Quit );
}

Image::~Image ( void )
{
NOM_LOG_TRACE ( NOM );
}

Image::Image ( uint32 flags ) : image_ ( nullptr, priv::FreeSurface )
{
NOM_LOG_TRACE ( NOM );

  if ( IMG_Init ( flags ) != flags )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
  }

  atexit ( IMG_Quit );
}

Image::Image ( const Image& other )  : image_ { other.image(), priv::FreeSurface }
{
NOM_LOG_TRACE ( NOM );
}

Image& Image::operator = ( const Image& other )
{
  this->image_ = other.image_;

  return *this;
}

bool Image::initialize( void* pixels, int32 width, int32 height,
                        int32 bits_per_pixel, uint16 pitch,
                        uint32 Rmask, uint32 Gmask, uint32 Bmask, uint32 Amask
                      )
{
NOM_LOG_TRACE ( NOM );

  this->image_.reset ( SDL_CreateRGBSurfaceFrom ( pixels, width, height, bits_per_pixel, pitch, Rmask, Gmask, Bmask, Amask ), priv::FreeSurface );
  //this->set_bounds ( Coords ( 0, 0, width, height ) );

  if ( this->valid() == false )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::initialize ( int32 width, int32 height, uint8 bits_per_pixel, uint32 Rmask, uint32 Gmask, uint32 Bmask, uint32 Amask, bool colorkey )
{
NOM_LOG_TRACE ( NOM );

  this->image_.reset ( SDL_CreateRGBSurface ( 0, width, height, bits_per_pixel, Rmask, Gmask, Bmask, Amask ), priv::FreeSurface );
  //this->set_bounds ( Coords ( 0, 0, width, height ) );

  if ( this->valid() == false )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  // If the video surface is marked for color keying transparency, we need to
  // set it up here and now!
  if ( colorkey )
  {
    if ( this->set_colorkey ( this->colorkey(), true ) == false )
    {
      NOM_LOG_ERR ( NOM, "Could not create the video surface with color key transparency." );
      return false;
    }
  }

  return true;
}

SDL_SURFACE::RawPtr Image::image ( void ) const
{
  return this->image_.get();
}

bool Image::valid ( void ) const
{
  if ( this->image() != nullptr ) return true;

  return false;
}

int32 Image::width ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->w;
}

int32 Image::height ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->h;
}

void* Image::pixels ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->pixels;
}

uint16 Image::pitch ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->pitch;
}

uint8 Image::bits_per_pixel ( void ) const
{
  SDL_Surface* buffer = this->image();

  return buffer->format->BitsPerPixel;
}

const SDL_PIXELFORMAT::RawPtr Image::pixel_format ( void ) const
{
  SDL_Surface* buffer = this->image();
  return buffer->format;
}

const uint32 Image::red_mask ( void ) const
{
  return this->pixel_format()->Rmask;
}

const uint32 Image::green_mask ( void ) const
{
  return this->pixel_format()->Gmask;
}

const uint32 Image::blue_mask ( void ) const
{
  return this->pixel_format()->Bmask;
}

const uint32 Image::alpha_mask ( void ) const
{
  return this->pixel_format()->Amask;
}

const Coords Image::bounds ( void ) const
{
  SDL_Rect clip_buffer; // temporary storage struct
  Coords clip_bounds; // transferred values from SDL_Rect clip_buffer

  // Return values are put into the clip_buffer SDL_Rect after executing:
  SDL_GetClipRect ( this->image(), &clip_buffer );

  // Now transfer the values into our preferred data container type
  clip_bounds = Coords ( clip_buffer.x, clip_buffer.y, clip_buffer.w, clip_buffer.h );

  return clip_bounds;
}

bool Image::must_lock ( void ) const
{
  if ( SDL_MUSTLOCK ( this->image() ) ) return true;

  return false;
}

bool Image::locked ( void ) const
{
  return this->image()->locked;
}

const uint8 Image::alpha ( void ) const
{
  uint8 alpha;

  if ( SDL_GetSurfaceAlphaMod ( this->image(), &alpha ) != 0 )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return 0;
  }

  return alpha;
}

void Image::set_bounds ( const Coords& clip_bounds )
{
  SDL_Rect clip = SDL_RECT ( clip_bounds );

  // As per libSDL docs, if SDL_Rect is nullptr, the clipping rectangle is set
  // to the full size of the surface
  SDL_SetClipRect ( this->image(), &clip );
}

bool Image::load ( const std::string& filename )
{
  SDL_Surface *buffer = IMG_Load ( filename.c_str() );

  if ( buffer == nullptr )
  {
NOM_LOG_ERR ( NOM, IMG_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  this->image_.reset ( SDL_ConvertSurfaceFormat ( buffer, SDL_PIXELFORMAT_ARGB8888, 0 ), priv::FreeSurface );
  priv::FreeSurface ( buffer );

  return true;
}

bool Image::load_bmp ( const std::string& filename )
{
  SDL_Surface *buffer = IMG_Load ( filename.c_str() );
  if ( buffer == nullptr )
  {
    NOM_LOG_ERR ( NOM, IMG_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  this->image_.reset ( SDL_ConvertSurfaceFormat ( buffer, SDL_PIXELFORMAT_ARGB8888, 0 ), priv::FreeSurface );
  priv::FreeSurface ( buffer );

  return true;
}

bool Image::save ( const std::string& filename, SDL_SURFACE::RawPtr video_buffer ) const
{
  if ( SDL_SaveBMP ( video_buffer, filename.c_str() ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::save ( const std::string& filename ) const
{
  if ( this->save( filename, this->image() ) == false ) return false;

  // Success!
  return true;
}

bool Image::save_png ( const std::string& filename ) const
{
  // Undocumented method for writing out a PNG file with SDL2_image
  if ( IMG_SavePNG ( this->image(), filename.c_str() ) != 0 )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

const Point2i Image::size ( void ) const
{
  SDL_Surface* buffer = this->image();
  Point2i image_pos ( buffer->w, buffer->h );

  return image_pos;
}

const Color4u Image::colorkey ( void ) const
{
  SDL_Surface* buffer = this->image();
  uint32 transparent_color = 0;
  Color4u key;

  if ( SDL_GetColorKey ( this->image(), &transparent_color ) != 0 )
  {
    NOM_LOG_ERR ( NOM, SDL_GetError() );
    return NOM_COLOR4U_BLACK;
  }

  return nom::pixel ( transparent_color, buffer->format ); // SDL_helper function
}

const SDL_BlendMode Image::blend_mode ( void ) const
{
  SDL_BlendMode blend;

  if ( SDL_GetSurfaceBlendMode ( this->image(), &blend ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return blend;
  }

  return blend;
}

bool Image::set_colorkey ( const Color4u& colorkey, bool flag )
{
  SDL_Surface* buffer = this->image();
  uint32 transparent_color = RGB ( colorkey, buffer->format );

  if ( this->valid() == false )
  {
NOM_LOG_ERR ( NOM, "Could not set color key: invalid image buffer." );
    priv::FreeSurface ( buffer );
    return false;
  }

  if ( SDL_SetColorKey ( buffer, SDL_BOOL(flag), transparent_color ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    priv::FreeSurface ( buffer );
    return false;
  }

  return true;
}

bool Image::RLE ( bool flag )
{
  if ( SDL_SetSurfaceRLE ( this->image(), SDL_BOOL(flag) ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }
  return true;
}

uint32 Image::pixel ( int32 x, int32 y )
{
  switch ( this->bits_per_pixel() )
  {
    default: return -1; break; // Unknown

    case 8:
    {
      uint8* pixels = static_cast<uint8*> ( this->pixels() );

      return pixels[ ( y * this->pitch() ) + x ];
    }
    break;

    case 16:
    {
      uint16* pixels = static_cast<uint16*> ( this->pixels() );

      return pixels[ ( y * this->pitch() / 2 ) + x ];
    }
    break;

    case 24:
    {
      uint8* pixels = static_cast<uint8*> ( this->pixels() );

      return pixels[ ( y * this->pitch() ) + x ];
    }
    break;

    case 32:
    {
      uint32* pixels = static_cast<uint32*> ( this->pixels() );

      return pixels[ ( y * this->pitch()/4 ) + x ];
    }
    break;
  } // end switch
}

bool Image::set_blend_mode ( const SDL_BlendMode blend )
{
  if ( SDL_SetSurfaceBlendMode ( this->image(), blend ) != 0 )
  {
NOM_LOG_ERR ( NOM, SDL_GetError() );
    return false;
  }

  return true;
}

bool Image::lock ( void ) const
{
  if ( SDL_BOOL ( this->must_lock() ) )
  {
    if ( SDL_LockSurface ( this->image() ) != 0 )
    {
NOM_LOG_ERR ( NOM, "Could not lock video surface memory." );
      return false;
    }
  }

  return true;
}

void Image::unlock ( void ) const
{
  SDL_UnlockSurface ( this->image() );
}

} // namespace nom
<|endoftext|>


<commit_before>
/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include "Sofa_test.h"
#include <SofaBoundaryCondition/PointConstraint.h>
#include <sofa/defaulttype/VecTypes.h>
#include <sofa/simulation/common/Simulation.h>
#include <sofa/simulation/graph/DAGSimulation.h>
#include <sofa/simulation/common/Node.h>
#include <SofaBaseMechanics/MechanicalObject.h>
#include <SofaBaseMechanics/UniformMass.h>
#include <plugins/SceneCreator/SceneCreator.h>
#include <SofaBoundaryCondition/ConstantForceField.h>

namespace sofa{
namespace {
using namespace modeling;

template<typename DataTypes>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<DataTypes>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<DataTypes, typename DataTypes::Real> >());
}

template<>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<defaulttype::Rigid3Types>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<defaulttype::Rigid3Types, defaulttype::Rigid3Mass> >());
}

template<>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<defaulttype::Rigid2Types>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<defaulttype::Rigid2Types, defaulttype::Rigid2Mass> >());
}

template <typename _DataTypes>
struct PointConstraint_test : public Sofa_test<typename _DataTypes::Real>
{
    typedef _DataTypes DataTypes;
    typedef component::projectiveconstraintset::PointConstraint<DataTypes> PointConstraint;
    typedef component::forcefield::ConstantForceField<DataTypes> ForceField;
    typedef component::container::MechanicalObject<DataTypes> MechanicalObject;

    typedef typename MechanicalObject::VecCoord  VecCoord;
    typedef typename MechanicalObject::Coord  Coord;
    typedef typename MechanicalObject::VecDeriv  VecDeriv;
    typedef typename MechanicalObject::Deriv  Deriv;
    typedef typename DataTypes::Real  Real;
    typedef sofa::helper::fixed_array<bool,Deriv::total_size> VecBool;

    bool test(double epsilon)
    {
        //Init

        simulation::Simulation* simulation;
        sofa::simulation::setSimulation(simulation = new sofa::simulation::graph::DAGSimulation());
        Deriv force;
        for(unsigned i=0; i<force.size(); i++)
            force[i]=10;
        VecBool fixed;
        for(unsigned i=0; i<fixed.size(); i++)
            fixed[i]=false;

        /// Scene creation
        simulation::Node::SPtr root = simulation->createNewGraph("root");
        root->setGravity( defaulttype::Vector3(0,0,0) );

        simulation::Node::SPtr node = createEulerSolverNode(root,"test");

        typename MechanicalObject::SPtr dofs = addNew<MechanicalObject>(node);
        dofs->resize(1);

        createUniformMass<DataTypes>(node, *dofs.get());

        typename ForceField::SPtr forceField = addNew<ForceField>(node);
        forceField->setForce( 0, force );

        typename PointConstraint::SPtr constraint = addNew<PointConstraint>(node);

        // Init simulation
        sofa::simulation::getSimulation()->init(root.get());

        for(unsigned i=0; i<fixed.size(); i++)
        {
            fixed[i] = true;
            helper::vector<unsigned int> fixed_indices;
            fixed_indices.push_back(0);
            constraint->f_indices.setValue(fixed_indices);

            // Perform one time step
            sofa::simulation::getSimulation()->animate(root.get(),0.5);

            // Check if the particle moved in a fixed direction
            typename MechanicalObject::ReadVecDeriv readV = dofs->readVelocities();
            if( readV[0][i]>epsilon )
            {
                ADD_FAILURE() << "Error: non null velocity in direction " << i << endl;
                return false;
            }

            sofa::simulation::getSimulation()->reset(root.get());
            fixed[i] = false;
        }

        return true;

    }
};

// Define the list of DataTypes to instanciate
using testing::Types;
typedef Types<
    defaulttype::Vec1Types,
    defaulttype::Vec2Types,
    defaulttype::Vec3Types,
    defaulttype::Vec6Types,
    defaulttype::Rigid2Types,
    defaulttype::Rigid3Types
> DataTypes; // the types to instanciate.

// Test suite for all the instanciations
TYPED_TEST_CASE(PointConstraint_test, DataTypes);
// first test case
TYPED_TEST( PointConstraint_test , testValue )
{
    EXPECT_TRUE(  this->test(1e-8) );
}

}// namespace
}// namespace sofa

<commit_msg>ADD: PointConstraint test<commit_after>
/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include "Sofa_test.h"
#include <SofaBoundaryCondition/PointConstraint.h>
#include <sofa/defaulttype/VecTypes.h>
#include <sofa/simulation/common/Simulation.h>
#include <sofa/simulation/graph/DAGSimulation.h>
#include <sofa/simulation/common/Node.h>
#include <SofaBaseMechanics/MechanicalObject.h>
#include <SofaBaseMechanics/UniformMass.h>
#include <plugins/SceneCreator/SceneCreator.h>
#include <SofaBoundaryCondition/ConstantForceField.h>

namespace sofa{
namespace {
using namespace modeling;

template<typename DataTypes>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<DataTypes>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<DataTypes, typename DataTypes::Real> >());
}

template<>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<defaulttype::Rigid3Types>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<defaulttype::Rigid3Types, defaulttype::Rigid3Mass> >());
}

template<>
void createUniformMass(simulation::Node::SPtr node, component::container::MechanicalObject<defaulttype::Rigid2Types>& dofs)
{
    node->addObject(sofa::core::objectmodel::New<component::mass::UniformMass<defaulttype::Rigid2Types, defaulttype::Rigid2Mass> >());
}

template <typename _DataTypes>
struct PointConstraint_test : public Sofa_test<typename _DataTypes::Real>
{
    typedef _DataTypes DataTypes;
    typedef component::projectiveconstraintset::PointConstraint<DataTypes> PointConstraint;
    typedef component::forcefield::ConstantForceField<DataTypes> ForceField;
    typedef component::container::MechanicalObject<DataTypes> MechanicalObject;

    typedef typename MechanicalObject::VecCoord  VecCoord;
    typedef typename MechanicalObject::Coord  Coord;
    typedef typename MechanicalObject::VecDeriv  VecDeriv;
    typedef typename MechanicalObject::Deriv  Deriv;
    typedef typename DataTypes::Real  Real;
    typedef sofa::helper::fixed_array<bool,Deriv::total_size> VecBool;

    bool test(double epsilon)
    {
        //Init

        simulation::Simulation* simulation;
        sofa::simulation::setSimulation(simulation = new sofa::simulation::graph::DAGSimulation());
        Deriv force;
        for(unsigned i=0; i<force.size(); i++)
            force[i]=10;
        VecBool fixed;
        for(unsigned i=0; i<fixed.size(); i++)
            fixed[i]=false;

        /// Scene creation
        simulation::Node::SPtr root = simulation->createNewGraph("root");
        root->setGravity( defaulttype::Vector3(0,0,0) );

        simulation::Node::SPtr node = createEulerSolverNode(root,"test");

        typename MechanicalObject::SPtr dofs = addNew<MechanicalObject>(node);
        dofs->resize(1);

        createUniformMass<DataTypes>(node, *dofs.get());

        typename ForceField::SPtr forceField = addNew<ForceField>(node);
        forceField->setForce( 0, force );

        typename PointConstraint::SPtr constraint = addNew<PointConstraint>(node);

        // Init simulation
        sofa::simulation::getSimulation()->init(root.get());

        for(unsigned i=0; i<fixed.size(); i++)
        {
            fixed[i] = true;
            helper::vector<unsigned int> fixed_indices;
            fixed_indices.push_back(0);
            constraint->f_indices.setValue(fixed_indices);

            // Perform one time step
            sofa::simulation::getSimulation()->animate(root.get(),0.5);

            // Check if the particle moved in a fixed direction
            typename MechanicalObject::ReadVecDeriv readV = dofs->readVelocities();
            if( readV[0][i]>epsilon )
            {
                ADD_FAILURE() << "Error: non null velocity in direction " << i << endl;
                return false;
            }

            sofa::simulation::getSimulation()->reset(root.get());
            fixed[i] = false;
        }

        return true;

    }
};

// Define the list of DataTypes to instanciate
using testing::Types;
typedef Types<
    defaulttype::Vec3Types
> DataTypes; // the types to instanciate.

// Test suite for all the instanciations
TYPED_TEST_CASE(PointConstraint_test, DataTypes);
// first test case
TYPED_TEST( PointConstraint_test , testValue )
{
    EXPECT_TRUE(  this->test(1e-8) );
}

}// namespace
}// namespace sofa

<|endoftext|>


<commit_before>/** \brief Utility for displaying various bits of info about a collection of MARC records.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015,2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <stdexcept>
#include <unordered_set>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include "Leader.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "util.h"

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "Usage: " << progname << " [--verbose] marc_data\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecords(const bool verbose, const bool input_is_xml, File * const input) {
    std::string raw_record;
    unsigned record_count(0), max_record_length(0), max_local_block_count(0);
    std::unordered_set<std::string> control_numbers;
    std::map<Leader::RecordType, unsigned> record_types_and_counts;

    while (const MarcUtil::Record record =
           input_is_xml ? MarcUtil::Record::XmlFactory(input) : MarcUtil::Record::BinaryFactory(input))
    {
        ++record_count;

        const std::vector<std::string> &fields(record.getFields());
        if (unlikely(fields.empty()))
          Error("record #" + std::to_string(record_count) + " has zero fields!");
        const std::string &control_number(fields[0]);

        const Leader::RecordType record_type(record.getRecordType());
        ++record_types_and_counts[record_type];
        if (verbose and record_type == Leader::RecordType::UNKNOWN)
            std::cerr << "Unknown record type '" << record.getLeader()[6] << "' for PPN " << control_number << ".\n";

        std::string err_msg;
        if (not input_is_xml and not record.recordSeemsCorrect(&err_msg))
            Error("record #" + std::to_string(record_count) + " is malformed: " + err_msg);

        if (control_numbers.find(control_number) != control_numbers.end())
            Error("found at least one duplicate control number: " + control_number);
        control_numbers.insert(control_number);

        const Leader &leader(record.getLeader());
        const unsigned record_length(leader.getRecordLength());
        if (record_length > max_record_length)
            max_record_length = record_length;

        std::vector<std::pair<size_t, size_t>> local_block_boundaries;
        const size_t local_block_count(record.findAllLocalDataBlocks(&local_block_boundaries));
        if (local_block_count > max_local_block_count)
            max_local_block_count = local_block_count;
    }

    std::cout << "Data set contains " << record_count << " MARC record(s).\n";
    std::cout << "Largest record contains " << max_record_length << " bytes.\n";
    std::cout << "The record with the largest number of \"local\" blocks has " << max_local_block_count
              << " local blocks.\n";
    std::cout << "Counted " << record_types_and_counts[Leader::RecordType::BIBLIOGRAPHIC]
              << " bibliographic record(s), " << record_types_and_counts[Leader::RecordType::AUTHORITY]
              << " classification record(s), " << record_types_and_counts[Leader::RecordType::CLASSIFICATION]
              << " authority record(s), and " << record_types_and_counts[Leader::RecordType::UNKNOWN]
              << " record(s) of unknown record type.\n";
}

int main(int argc, char *argv[]) {
    progname = argv[0];

    if (argc < 2)
        Usage();

    const bool verbose(std::strcmp(argv[1], "--verbose") == 0);
    if (verbose)
        --argc, ++argv;

    if (argc != 2)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string media_type(MediaTypeUtil::GetFileMediaType(marc_input_filename));
    if (unlikely(media_type.empty()))
        Error("can't determine media type of \"" + marc_input_filename + "\"!");
    if (media_type != "application/xml" and media_type != "application/marc")
        Error("\"input_filename\" is neither XML nor MARC-21 data!");
    const bool input_is_xml(media_type == "application/xml");

    File marc_input(marc_input_filename, "r");
    if (not marc_input)
        Error("can't open \"" + marc_input_filename + "\" for reading!");

    try {
        ProcessRecords(verbose, input_is_xml, &marc_input);
    } catch (const std::exception &e) {
        Error("Caught exception: " + std::string(e.what()));
    }
}
<commit_msg>Now also Reporting the number of oversized records.<commit_after>/** \brief Utility for displaying various bits of info about a collection of MARC records.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2015,2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <stdexcept>
#include <unordered_set>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include "Leader.h"
#include "MarcUtil.h"
#include "MediaTypeUtil.h"
#include "util.h"

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "Usage: " << progname << " [--verbose] marc_data\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecords(const bool verbose, const bool input_is_xml, File * const input) {
    std::string raw_record;
    unsigned record_count(0), max_record_length(0), max_local_block_count(0), oversized_record_count(0);
    std::unordered_set<std::string> control_numbers;
    std::map<Leader::RecordType, unsigned> record_types_and_counts;

    while (const MarcUtil::Record record =
           input_is_xml ? MarcUtil::Record::XmlFactory(input) : MarcUtil::Record::BinaryFactory(input))
    {
        ++record_count;

        const std::vector<std::string> &fields(record.getFields());
        if (unlikely(fields.empty()))
          Error("record #" + std::to_string(record_count) + " has zero fields!");
        const std::string &control_number(fields[0]);

        const Leader::RecordType record_type(record.getRecordType());
        ++record_types_and_counts[record_type];
        if (verbose and record_type == Leader::RecordType::UNKNOWN)
            std::cerr << "Unknown record type '" << record.getLeader()[6] << "' for PPN " << control_number << ".\n";

        std::string err_msg;
        if (not input_is_xml and not record.recordSeemsCorrect(&err_msg))
            Error("record #" + std::to_string(record_count) + " is malformed: " + err_msg);

        if (control_numbers.find(control_number) != control_numbers.end())
            Error("found at least one duplicate control number: " + control_number);
        control_numbers.insert(control_number);

        const Leader &leader(record.getLeader());
        const unsigned record_length(leader.getRecordLength());
        if (record_length > max_record_length)
            max_record_length = record_length;
        if (record_length >= 100000)
            ++oversized_record_count;

        std::vector<std::pair<size_t, size_t>> local_block_boundaries;
        const size_t local_block_count(record.findAllLocalDataBlocks(&local_block_boundaries));
        if (local_block_count > max_local_block_count)
            max_local_block_count = local_block_count;
    }

    std::cout << "Data set contains " << record_count << " MARC record(s).\n";
    std::cout << "Largest record contains " << max_record_length << " bytes.\n";
    std::cout << "The record with the largest number of \"local\" blocks has " << max_local_block_count
              << " local blocks.\n";
    std::cout << "Counted " << record_types_and_counts[Leader::RecordType::BIBLIOGRAPHIC]
              << " bibliographic record(s), " << record_types_and_counts[Leader::RecordType::AUTHORITY]
              << " classification record(s), " << record_types_and_counts[Leader::RecordType::CLASSIFICATION]
              << " authority record(s), and " << record_types_and_counts[Leader::RecordType::UNKNOWN]
              << " record(s) of unknown record type.\n";
    std::cout << "Found " << oversized_record_count << " oversized records.\n";
}

int main(int argc, char *argv[]) {
    progname = argv[0];

    if (argc < 2)
        Usage();

    const bool verbose(std::strcmp(argv[1], "--verbose") == 0);
    if (verbose)
        --argc, ++argv;

    if (argc != 2)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string media_type(MediaTypeUtil::GetFileMediaType(marc_input_filename));
    if (unlikely(media_type.empty()))
        Error("can't determine media type of \"" + marc_input_filename + "\"!");
    if (media_type != "application/xml" and media_type != "application/marc")
        Error("\"input_filename\" is neither XML nor MARC-21 data!");
    const bool input_is_xml(media_type == "application/xml");

    File marc_input(marc_input_filename, "r");
    if (not marc_input)
        Error("can't open \"" + marc_input_filename + "\" for reading!");

    try {
        ProcessRecords(verbose, input_is_xml, &marc_input);
    } catch (const std::exception &e) {
        Error("Caught exception: " + std::string(e.what()));
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. 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
 *
 * 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 "modules/perception/obstacle/fusion/probabilistic_fusion/pbf_imf_fusion.h"
#include "modules/perception/obstacle/fusion/probabilistic_fusion/pbf_kalman_motion_fusion.h"

#include <algorithm>
#include <functional>
#include <map>
#include <random>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "modules/common/log.h"

namespace apollo {
namespace perception {

class PbfMotionFusionTest : public testing::Test {
 protected:
  PbfMotionFusionTest() {}
  ~PbfMotionFusionTest() {}
  void SetUp() override {
    PbfBaseMotionFusion *kalman_motion_fusion = new PbfKalmanMotionFusion();
    PbfIMFFusion *imf_motion_fusion = new PbfIMFFusion();
    motion_fusion_algs_.push_back(kalman_motion_fusion);
    motion_fusion_algs_.push_back(imf_motion_fusion);
    LidarFrameSupplement::state_vars.initialized_ = true;
    RadarFrameSupplement::state_vars.initialized_ = true;
    CameraFrameSupplement::state_vars.initialized_ = true;
    PbfTrack::SetMaxLidarInvisiblePeriod(10);
    PbfTrack::SetMaxRadarInvisiblePeriod(10);
    PbfTrack::SetMaxCameraInvisiblePeriod(10);
  }
  void TearDown() override {
    for (auto &seg_alg : motion_fusion_algs_) {
      delete seg_alg;
    }
    std::vector<PbfBaseMotionFusion *>().swap(motion_fusion_algs_);
  }

 protected:
  std::vector<PbfBaseMotionFusion *> motion_fusion_algs_;
};

TEST_F(PbfMotionFusionTest, test_initialize_with_lidar_object) {
  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.012;
  Eigen::Vector3d lidar_position(30, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  lidar_object->state_uncertainty.setIdentity();
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_lidar_object);
    CHECK_EQ(motion_fusion_alg->Initialized(), true);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - lidar_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-6);
  }
}
TEST_F(PbfMotionFusionTest, test_initialize_with_radar_object) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.112;
  Eigen::Vector3d radar_position(31.1, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_radar_object);
    CHECK_EQ(motion_fusion_alg->Initialized(), true);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - radar_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - radar_velocity).norm() < 1.0e-6);
  }
}
TEST_F(PbfMotionFusionTest, test_update_with_measurement_kalman) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));

  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.112;
  Eigen::Vector3d lidar_position(31.01, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfKalmanMotionFusion") {
      continue;
    }
    motion_fusion_alg->setCurrentFuseTS(radar_timestamp + 0.2);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp + 0.2);
    motion_fusion_alg->setCurrentFuseTS(lidar_timestamp + 0.2);
    motion_fusion_alg->UpdateWithObject(pbf_lidar_object,
                                        lidar_timestamp - radar_timestamp);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    std::cout << "algorithm " << motion_fusion_alg->name() << ": " << location
              << lidar_position << (location - lidar_position).norm();
    EXPECT_TRUE((location - lidar_position).norm() < 2.0e-1);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-1);
  }
}

TEST_F(PbfMotionFusionTest, test_update_with_measurement_imf) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));

  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.112;
  Eigen::Vector3d lidar_position(31.01, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));

  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfInformationMotionFusion") continue;

    motion_fusion_alg->setCurrentFuseTS(radar_timestamp);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp);
    motion_fusion_alg->setCurrentFuseTS(lidar_timestamp + 0.2);
    motion_fusion_alg->UpdateWithObject(
        pbf_lidar_object, lidar_timestamp - radar_timestamp + 0.2);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    double time_diff = 0.2;
    AINFO << "algorithm " << motion_fusion_alg->name() << ": " << location
          << lidar_position + time_diff * lidar_velocity << velocity
          << lidar_velocity;
    EXPECT_TRUE(
        (location - (lidar_position + time_diff * lidar_velocity)).norm() <
        2.0e-1);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-1);
  }
}

TEST_F(PbfMotionFusionTest, test_update_with_measurement_imf_seq) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));
  pbf_radar_object->timestamp = radar_timestamp;
  std::default_random_engine generator;
  std::normal_distribution<double> distribution(0, 2);

  int steps = 10;

  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfInformationMotionFusion") continue;

    motion_fusion_alg->setCurrentFuseTS(radar_timestamp);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp);
    AINFO << "algorithm " << motion_fusion_alg->name() << " long sequence test";
    double mutable_radar_timestamp = radar_timestamp;
    Eigen::Vector3d ground_truth_location = radar_position;
    for (int i = 0; i < steps; ++i) {
      mutable_radar_timestamp += 0.1;
      // double measure_position_noise = distribution(generator);
      Eigen::Vector3d measure_position_noise_vec;
      // measure_position_noise_vec << measure_position_noise, 0, 0;
      measure_position_noise_vec << 0, 0, 0;
      ground_truth_location += radar_velocity * 0.1;
      std::shared_ptr<Object> radar_object(new Object());
      radar_object->center = ground_truth_location + measure_position_noise_vec;
      AINFO << "radar object center is " << radar_object->center(0);
      radar_object->anchor_point = radar_object->center;
      radar_object->velocity = radar_velocity;
      std::shared_ptr<PbfSensorObject> pbf_radar_object(new PbfSensorObject(
          radar_object, SensorType::RADAR, mutable_radar_timestamp));
      pbf_radar_object->timestamp = mutable_radar_timestamp;
      motion_fusion_alg->setCurrentFuseTS(mutable_radar_timestamp + 0.2);
      motion_fusion_alg->UpdateWithObject(pbf_radar_object,
                                          motion_fusion_alg->getFuseTimeDiff());
      motion_fusion_alg->setLastFuseTS(mutable_radar_timestamp + 0.2);
      Eigen::Vector3d location;
      Eigen::Vector3d velocity;
      ground_truth_location += 0.2 * radar_velocity;
      motion_fusion_alg->GetState(&location, &velocity);
      AINFO << "ground truth:" << ground_truth_location(0) << " "
            << radar_velocity(0);
      AINFO << "filtered value:" << location(0) << " " << velocity(0);
    }
  }
  EXPECT_TRUE(false);
}

TEST_F(PbfMotionFusionTest, test_update_without_measurement) {
  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.012;
  Eigen::Vector3d lidar_position(30, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));

  double time_diff = 0.1;
  Eigen::Vector3d expected_position =
      lidar_position + lidar_velocity * time_diff;
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_lidar_object);
    motion_fusion_alg->UpdateWithoutObject(time_diff);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - expected_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1e-3);
  }
}

}  // namespace perception
}  // namespace apollo
<commit_msg>Perception: fixed pbf_motion_fusion_test. (#4528)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. 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
 *
 * 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 "modules/perception/obstacle/fusion/probabilistic_fusion/pbf_imf_fusion.h"
#include "modules/perception/obstacle/fusion/probabilistic_fusion/pbf_kalman_motion_fusion.h"

#include <algorithm>
#include <functional>
#include <map>
#include <random>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "modules/common/log.h"

namespace apollo {
namespace perception {

class PbfMotionFusionTest : public testing::Test {
 protected:
  PbfMotionFusionTest() {}
  ~PbfMotionFusionTest() {}
  void SetUp() override {
    PbfBaseMotionFusion *kalman_motion_fusion = new PbfKalmanMotionFusion();
    PbfIMFFusion *imf_motion_fusion = new PbfIMFFusion();
    motion_fusion_algs_.push_back(kalman_motion_fusion);
    motion_fusion_algs_.push_back(imf_motion_fusion);
    LidarFrameSupplement::state_vars.initialized_ = true;
    RadarFrameSupplement::state_vars.initialized_ = true;
    CameraFrameSupplement::state_vars.initialized_ = true;
    PbfTrack::SetMaxLidarInvisiblePeriod(10);
    PbfTrack::SetMaxRadarInvisiblePeriod(10);
    PbfTrack::SetMaxCameraInvisiblePeriod(10);
  }
  void TearDown() override {
    for (auto &seg_alg : motion_fusion_algs_) {
      delete seg_alg;
    }
    std::vector<PbfBaseMotionFusion *>().swap(motion_fusion_algs_);
  }

 protected:
  std::vector<PbfBaseMotionFusion *> motion_fusion_algs_;
};

TEST_F(PbfMotionFusionTest, test_initialize_with_lidar_object) {
  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.012;
  Eigen::Vector3d lidar_position(30, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  lidar_object->state_uncertainty.setIdentity();
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_lidar_object);
    CHECK_EQ(motion_fusion_alg->Initialized(), true);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - lidar_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-6);
  }
}
TEST_F(PbfMotionFusionTest, test_initialize_with_radar_object) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.112;
  Eigen::Vector3d radar_position(31.1, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_radar_object);
    CHECK_EQ(motion_fusion_alg->Initialized(), true);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - radar_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - radar_velocity).norm() < 1.0e-6);
  }
}
TEST_F(PbfMotionFusionTest, test_update_with_measurement_kalman) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));

  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.112;
  Eigen::Vector3d lidar_position(31.01, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfKalmanMotionFusion") {
      continue;
    }
    motion_fusion_alg->setCurrentFuseTS(radar_timestamp + 0.2);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp + 0.2);
    motion_fusion_alg->setCurrentFuseTS(lidar_timestamp + 0.2);
    motion_fusion_alg->UpdateWithObject(pbf_lidar_object,
                                        lidar_timestamp - radar_timestamp);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    std::cout << "algorithm " << motion_fusion_alg->name() << ": " << location
              << lidar_position << (location - lidar_position).norm();
    EXPECT_TRUE((location - lidar_position).norm() < 2.0e-1);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-1);
  }
}

TEST_F(PbfMotionFusionTest, test_update_with_measurement_imf) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));

  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.112;
  Eigen::Vector3d lidar_position(31.01, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));

  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfInformationMotionFusion") continue;

    motion_fusion_alg->setCurrentFuseTS(radar_timestamp);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp);
    motion_fusion_alg->setCurrentFuseTS(lidar_timestamp + 0.2);
    motion_fusion_alg->UpdateWithObject(
        pbf_lidar_object, lidar_timestamp - radar_timestamp + 0.2);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    double time_diff = 0.2;
    AINFO << "algorithm " << motion_fusion_alg->name() << ": " << location
          << lidar_position + time_diff * lidar_velocity << velocity
          << lidar_velocity;
    EXPECT_TRUE(
        (location - (lidar_position + time_diff * lidar_velocity)).norm() <
        2.0e-1);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1.0e-1);
  }
}

TEST_F(PbfMotionFusionTest, test_update_with_measurement_imf_seq) {
  std::shared_ptr<Object> radar_object(new Object());
  double radar_timestamp = 1234567891.012;
  Eigen::Vector3d radar_position(30, 0, 0);
  Eigen::Vector3d radar_velocity(10.01, 0, 0);
  radar_object->center = radar_position;
  radar_object->anchor_point = radar_position;
  radar_object->velocity = radar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_radar_object(
      new PbfSensorObject(radar_object, SensorType::RADAR, radar_timestamp));
  pbf_radar_object->timestamp = radar_timestamp;
  std::default_random_engine generator;
  std::normal_distribution<double> distribution(0, 2);

  int steps = 10;

  for (auto motion_fusion_alg : motion_fusion_algs_) {
    if (motion_fusion_alg->name() != "PbfInformationMotionFusion") continue;

    motion_fusion_alg->setCurrentFuseTS(radar_timestamp);
    motion_fusion_alg->Initialize(pbf_radar_object);
    motion_fusion_alg->setLastFuseTS(radar_timestamp);
    AINFO << "algorithm " << motion_fusion_alg->name() << " long sequence test";
    double mutable_radar_timestamp = radar_timestamp;
    Eigen::Vector3d ground_truth_location = radar_position;
    for (int i = 0; i < steps; ++i) {
      mutable_radar_timestamp += 0.1;
      // double measure_position_noise = distribution(generator);
      Eigen::Vector3d measure_position_noise_vec;
      // measure_position_noise_vec << measure_position_noise, 0, 0;
      measure_position_noise_vec << 0, 0, 0;
      ground_truth_location += radar_velocity * 0.1;
      std::shared_ptr<Object> radar_object(new Object());
      radar_object->center = ground_truth_location + measure_position_noise_vec;
      AINFO << "radar object center is " << radar_object->center(0);
      radar_object->anchor_point = radar_object->center;
      radar_object->velocity = radar_velocity;
      std::shared_ptr<PbfSensorObject> pbf_radar_object(new PbfSensorObject(
          radar_object, SensorType::RADAR, mutable_radar_timestamp));
      pbf_radar_object->timestamp = mutable_radar_timestamp;
      motion_fusion_alg->setCurrentFuseTS(mutable_radar_timestamp + 0.2);
      motion_fusion_alg->UpdateWithObject(pbf_radar_object,
                                          motion_fusion_alg->getFuseTimeDiff());
      motion_fusion_alg->setLastFuseTS(mutable_radar_timestamp + 0.2);
      Eigen::Vector3d location;
      Eigen::Vector3d velocity;
      ground_truth_location += 0.2 * radar_velocity;
      motion_fusion_alg->GetState(&location, &velocity);
      AINFO << "ground truth:" << ground_truth_location(0) << " "
            << radar_velocity(0);
      AINFO << "filtered value:" << location(0) << " " << velocity(0);
    }
  }
}

TEST_F(PbfMotionFusionTest, test_update_without_measurement) {
  std::shared_ptr<Object> lidar_object(new Object());
  double lidar_timestamp = 1234567891.012;
  Eigen::Vector3d lidar_position(30, 0, 0);
  Eigen::Vector3d lidar_velocity(10, 0, 0);
  lidar_object->center = lidar_position;
  lidar_object->anchor_point = lidar_position;
  lidar_object->velocity = lidar_velocity;
  std::shared_ptr<PbfSensorObject> pbf_lidar_object(new PbfSensorObject(
      lidar_object, SensorType::VELODYNE_64, lidar_timestamp));

  double time_diff = 0.1;
  Eigen::Vector3d expected_position =
      lidar_position + lidar_velocity * time_diff;
  for (auto motion_fusion_alg : motion_fusion_algs_) {
    motion_fusion_alg->Initialize(pbf_lidar_object);
    motion_fusion_alg->UpdateWithoutObject(time_diff);
    Eigen::Vector3d location;
    Eigen::Vector3d velocity;
    motion_fusion_alg->GetState(&location, &velocity);
    EXPECT_TRUE((location - expected_position).norm() < 1.0e-6);
    EXPECT_TRUE((velocity - lidar_velocity).norm() < 1e-3);
  }
}

}  // namespace perception
}  // namespace apollo
<|endoftext|>


<commit_before>#include "catch.hpp"
#include "unistd.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>

#include "imageflow.h"

#include "imageflow_private.h"
#include "string.h"
#include "helpers.h"

#define ERR(c) REQUIRE_FALSE(flow_context_print_and_exit_if_err(c))

TEST_CASE("Test flow_snprintf with single-character buffer", "")
{
    char buf[] = { 3, 25 };
    REQUIRE(flow_snprintf(&buf[0], 1, "hello") == -1);
    REQUIRE(buf[0] == 0); // It should have written the null character
    REQUIRE(buf[1] == 25); // It should have left the last character untouched
}

TEST_CASE("Test flow_snprintf with zero-character buffer", "")
{
    char buf[] = { 25 };
    REQUIRE(flow_snprintf(&buf[0], 0, "hello") == -1);
    REQUIRE(buf[0] == 25); // It shouldn't have written past the size
}

TEST_CASE("Test flow_snprintf with a sufficient buffer", "")
{
    char buf[8];
    buf[7] = 25;
    REQUIRE(flow_snprintf(&buf[0], 6, "hello") == 5);

    REQUIRE(buf[6] == 0); // It should have written the null
    REQUIRE(buf[7] == 25); // It shouldn't have written past the size
}

TEST_CASE("Test context creation", "")
{
    flow_context* c = flow_context_create();
    ERR(c);
    flow_context_destroy(c);
}

TEST_CASE("Test error message printing", "")
{
    flow_context* c = flow_context_create();
    ERR(c);

    FLOW_error_msg(c, flow_status_Invalid_argument, "You passed a value outside [0,1]: %d", 3);
    char buf[4096];
    int chars_written = flow_context_error_and_stacktrace(c, buf, 4096, false);
    REQUIRE(chars_written > 0);
    REQUIRE(buf == std::string("Invalid argument : You passed a value outside [0,1]: 3\ntest_context.cpp:54: in "
                               "function ____C_A_T_C_H____T_E_S_T____49\n"));

    flow_context_destroy(c);
}

TEST_CASE("Test error message printing with null files or functions in the stacktrace", "")
{
    flow_context* c = flow_context_create();
    ERR(c);

    flow_context_raise_error(c, flow_status_Invalid_argument, NULL, NULL, 25, NULL);

    char buf[4096];
    int chars_written = flow_context_error_and_stacktrace(c, buf, 4096, false);
    REQUIRE(chars_written > 0);
    REQUIRE(buf == std::string("Invalid argument\n(unknown):25: in function (unknown)\n"));

    flow_context_destroy(c);
}
<commit_msg>Make error stacktrace test less fragile<commit_after>#include "catch.hpp"
#include "unistd.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>

#include "imageflow.h"

#include "imageflow_private.h"
#include "string.h"
#include "helpers.h"

#define ERR(c) REQUIRE_FALSE(flow_context_print_and_exit_if_err(c))

TEST_CASE("Test flow_snprintf with single-character buffer", "")
{
    char buf[] = { 3, 25 };
    REQUIRE(flow_snprintf(&buf[0], 1, "hello") == -1);
    REQUIRE(buf[0] == 0); // It should have written the null character
    REQUIRE(buf[1] == 25); // It should have left the last character untouched
}

TEST_CASE("Test flow_snprintf with zero-character buffer", "")
{
    char buf[] = { 25 };
    REQUIRE(flow_snprintf(&buf[0], 0, "hello") == -1);
    REQUIRE(buf[0] == 25); // It shouldn't have written past the size
}

TEST_CASE("Test flow_snprintf with a sufficient buffer", "")
{
    char buf[8];
    buf[7] = 25;
    REQUIRE(flow_snprintf(&buf[0], 6, "hello") == 5);

    REQUIRE(buf[6] == 0); // It should have written the null
    REQUIRE(buf[7] == 25); // It shouldn't have written past the size
}

TEST_CASE("Test context creation", "")
{
    flow_context* c = flow_context_create();
    ERR(c);
    flow_context_destroy(c);
}
using namespace Catch::Matchers;

TEST_CASE("Test error message printing", "")
{
    flow_context* c = flow_context_create();
    ERR(c);

    FLOW_error_msg(c, flow_status_Invalid_argument, "You passed a value outside [0,1]: %d", 3);
    char buf[4096];
    int chars_written = flow_context_error_and_stacktrace(c, buf, 4096, false);
    REQUIRE(chars_written > 0);
    REQUIRE_THAT( buf, StartsWith("Invalid argument : You passed a value outside [0,1]: 3\ntest_context.cpp:" ) );

    flow_context_destroy(c);
}

TEST_CASE("Test error message printing with null files or functions in the stacktrace", "")
{
    flow_context* c = flow_context_create();
    ERR(c);

    flow_context_raise_error(c, flow_status_Invalid_argument, NULL, NULL, 25, NULL);

    char buf[4096];
    int chars_written = flow_context_error_and_stacktrace(c, buf, 4096, false);
    REQUIRE(chars_written > 0);
    REQUIRE(buf == std::string("Invalid argument\n(unknown):25: in function (unknown)\n"));

    flow_context_destroy(c);
}
<|endoftext|>