backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)
This commit is contained in:
514
test/unit/zelda3/music_parser_test.cc
Normal file
514
test/unit/zelda3/music_parser_test.cc
Normal file
@@ -0,0 +1,514 @@
|
||||
#include "zelda3/music/spc_parser.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "zelda3/music/music_bank.h"
|
||||
#include "zelda3/music/song_data.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace test {
|
||||
|
||||
using namespace yaze::zelda3::music;
|
||||
|
||||
// =============================================================================
|
||||
// Song Data Tests
|
||||
// =============================================================================
|
||||
|
||||
class SongDataTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
};
|
||||
|
||||
TEST_F(SongDataTest, NoteGetNoteName_ValidPitches) {
|
||||
Note note;
|
||||
|
||||
// C1 = 0x80
|
||||
note.pitch = 0x80;
|
||||
EXPECT_EQ(note.GetNoteName(), "C1");
|
||||
|
||||
// C#1 = 0x81
|
||||
note.pitch = 0x81;
|
||||
EXPECT_EQ(note.GetNoteName(), "C#1");
|
||||
|
||||
// D1 = 0x82
|
||||
note.pitch = 0x82;
|
||||
EXPECT_EQ(note.GetNoteName(), "D1");
|
||||
|
||||
// C2 = 0x8C
|
||||
note.pitch = 0x8C;
|
||||
EXPECT_EQ(note.GetNoteName(), "C2");
|
||||
|
||||
// A4 = 0xAD (concert pitch)
|
||||
// Calculation: 0x80 + (octave-1)*12 + semitone
|
||||
// A is semitone 9, so A4 = 0x80 + 3*12 + 9 = 0x80 + 36 + 9 = 0xAD
|
||||
note.pitch = 0xAD;
|
||||
EXPECT_EQ(note.GetNoteName(), "A4");
|
||||
|
||||
// B6 = 0xC7 (highest note)
|
||||
note.pitch = 0xC7;
|
||||
EXPECT_EQ(note.GetNoteName(), "B6");
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, NoteGetNoteName_SpecialValues) {
|
||||
Note note;
|
||||
|
||||
// Tie
|
||||
note.pitch = kNoteTie;
|
||||
EXPECT_EQ(note.GetNoteName(), "---");
|
||||
|
||||
// Rest
|
||||
note.pitch = kNoteRest;
|
||||
EXPECT_EQ(note.GetNoteName(), "...");
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, NoteHelpers) {
|
||||
Note note;
|
||||
|
||||
note.pitch = 0x8C; // C2
|
||||
EXPECT_TRUE(note.IsNote());
|
||||
EXPECT_FALSE(note.IsTie());
|
||||
EXPECT_FALSE(note.IsRest());
|
||||
EXPECT_EQ(note.GetOctave(), 2);
|
||||
EXPECT_EQ(note.GetSemitone(), 0); // C
|
||||
|
||||
note.pitch = 0x8F; // D#2
|
||||
EXPECT_EQ(note.GetOctave(), 2);
|
||||
EXPECT_EQ(note.GetSemitone(), 3); // D#
|
||||
|
||||
note.pitch = kNoteTie;
|
||||
EXPECT_FALSE(note.IsNote());
|
||||
EXPECT_TRUE(note.IsTie());
|
||||
EXPECT_FALSE(note.IsRest());
|
||||
|
||||
note.pitch = kNoteRest;
|
||||
EXPECT_FALSE(note.IsNote());
|
||||
EXPECT_FALSE(note.IsTie());
|
||||
EXPECT_TRUE(note.IsRest());
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, MusicCommandParamCount) {
|
||||
MusicCommand cmd;
|
||||
|
||||
cmd.opcode = 0xE0; // SetInstrument
|
||||
EXPECT_EQ(cmd.GetParamCount(), 1);
|
||||
|
||||
cmd.opcode = 0xE3; // VibratoOn
|
||||
EXPECT_EQ(cmd.GetParamCount(), 3);
|
||||
|
||||
cmd.opcode = 0xE4; // VibratoOff
|
||||
EXPECT_EQ(cmd.GetParamCount(), 0);
|
||||
|
||||
cmd.opcode = 0xEF; // CallSubroutine
|
||||
EXPECT_EQ(cmd.GetParamCount(), 3);
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, MusicCommandSubroutine) {
|
||||
MusicCommand cmd;
|
||||
cmd.opcode = 0xEF;
|
||||
cmd.params = {0x00, 0xD0, 0x02}; // Address $D000, repeat 2
|
||||
|
||||
EXPECT_TRUE(cmd.IsSubroutine());
|
||||
EXPECT_EQ(cmd.GetSubroutineAddress(), 0xD000);
|
||||
EXPECT_EQ(cmd.GetSubroutineRepeatCount(), 2);
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, TrackEventFactory) {
|
||||
auto note_event = TrackEvent::MakeNote(100, 0x8C, 72, 0x40);
|
||||
EXPECT_EQ(note_event.type, TrackEvent::Type::Note);
|
||||
EXPECT_EQ(note_event.tick, 100);
|
||||
EXPECT_EQ(note_event.note.pitch, 0x8C);
|
||||
EXPECT_EQ(note_event.note.duration, 72);
|
||||
EXPECT_EQ(note_event.note.velocity, 0x40);
|
||||
|
||||
auto cmd_event = TrackEvent::MakeCommand(50, 0xE0, 0x0B);
|
||||
EXPECT_EQ(cmd_event.type, TrackEvent::Type::Command);
|
||||
EXPECT_EQ(cmd_event.tick, 50);
|
||||
EXPECT_EQ(cmd_event.command.opcode, 0xE0);
|
||||
EXPECT_EQ(cmd_event.command.params[0], 0x0B);
|
||||
|
||||
auto end_event = TrackEvent::MakeEnd(200);
|
||||
EXPECT_EQ(end_event.type, TrackEvent::Type::End);
|
||||
EXPECT_EQ(end_event.tick, 200);
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, MusicTrackDuration) {
|
||||
MusicTrack track;
|
||||
track.events.push_back(TrackEvent::MakeNote(0, 0x8C, 72));
|
||||
track.events.push_back(TrackEvent::MakeNote(72, 0x8E, 36));
|
||||
track.events.push_back(TrackEvent::MakeEnd(108));
|
||||
|
||||
track.CalculateDuration();
|
||||
|
||||
EXPECT_EQ(track.duration_ticks, 108);
|
||||
EXPECT_FALSE(track.is_empty);
|
||||
}
|
||||
|
||||
TEST_F(SongDataTest, MusicSegmentDuration) {
|
||||
MusicSegment segment;
|
||||
|
||||
// Track 0: 100 ticks
|
||||
segment.tracks[0].events.push_back(TrackEvent::MakeNote(0, 0x8C, 100));
|
||||
segment.tracks[0].CalculateDuration();
|
||||
|
||||
// Track 1: 200 ticks
|
||||
segment.tracks[1].events.push_back(TrackEvent::MakeNote(0, 0x8C, 200));
|
||||
segment.tracks[1].CalculateDuration();
|
||||
|
||||
// Other tracks empty
|
||||
for (int i = 2; i < 8; ++i) {
|
||||
segment.tracks[i].is_empty = true;
|
||||
segment.tracks[i].duration_ticks = 0;
|
||||
}
|
||||
|
||||
EXPECT_EQ(segment.GetDuration(), 200);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SpcParser Tests
|
||||
// =============================================================================
|
||||
|
||||
class SpcParserTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
};
|
||||
|
||||
TEST_F(SpcParserTest, GetCommandParamCount) {
|
||||
EXPECT_EQ(SpcParser::GetCommandParamCount(0xE0), 1); // SetInstrument
|
||||
EXPECT_EQ(SpcParser::GetCommandParamCount(0xE4), 0); // VibratoOff
|
||||
EXPECT_EQ(SpcParser::GetCommandParamCount(0xE7), 1); // SetTempo
|
||||
EXPECT_EQ(SpcParser::GetCommandParamCount(0xEF), 3); // CallSubroutine
|
||||
EXPECT_EQ(SpcParser::GetCommandParamCount(0x80), 0); // Not a command
|
||||
}
|
||||
|
||||
TEST_F(SpcParserTest, IsNotePitch) {
|
||||
EXPECT_TRUE(SpcParser::IsNotePitch(0x80)); // C1
|
||||
EXPECT_TRUE(SpcParser::IsNotePitch(0xC7)); // B6
|
||||
EXPECT_TRUE(SpcParser::IsNotePitch(0xC8)); // Tie
|
||||
EXPECT_TRUE(SpcParser::IsNotePitch(0xC9)); // Rest
|
||||
EXPECT_FALSE(SpcParser::IsNotePitch(0x7F)); // Duration
|
||||
EXPECT_FALSE(SpcParser::IsNotePitch(0xE0)); // Command
|
||||
}
|
||||
|
||||
TEST_F(SpcParserTest, IsDuration) {
|
||||
EXPECT_TRUE(SpcParser::IsDuration(0x00));
|
||||
EXPECT_TRUE(SpcParser::IsDuration(0x48)); // Quarter note
|
||||
EXPECT_TRUE(SpcParser::IsDuration(0x7F)); // Max duration
|
||||
EXPECT_FALSE(SpcParser::IsDuration(0x80)); // Note
|
||||
EXPECT_FALSE(SpcParser::IsDuration(0xE0)); // Command
|
||||
}
|
||||
|
||||
TEST_F(SpcParserTest, IsCommand) {
|
||||
EXPECT_TRUE(SpcParser::IsCommand(0xE0));
|
||||
EXPECT_TRUE(SpcParser::IsCommand(0xFF));
|
||||
EXPECT_FALSE(SpcParser::IsCommand(0xDF));
|
||||
EXPECT_FALSE(SpcParser::IsCommand(0x80));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SpcSerializer Tests
|
||||
// =============================================================================
|
||||
|
||||
class SpcSerializerTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
};
|
||||
|
||||
TEST_F(SpcSerializerTest, SerializeNote) {
|
||||
Note note;
|
||||
note.pitch = 0x8C;
|
||||
note.duration = 0x48;
|
||||
note.velocity = 0;
|
||||
note.has_duration_prefix = true;
|
||||
|
||||
uint8_t current_duration = 0;
|
||||
auto bytes = SpcSerializer::SerializeNote(note, ¤t_duration);
|
||||
|
||||
// Should output duration + pitch
|
||||
ASSERT_EQ(bytes.size(), 2);
|
||||
EXPECT_EQ(bytes[0], 0x48); // Duration
|
||||
EXPECT_EQ(bytes[1], 0x8C); // Pitch
|
||||
EXPECT_EQ(current_duration, 0x48);
|
||||
|
||||
// Next note with same duration
|
||||
Note note2;
|
||||
note2.pitch = 0x8E;
|
||||
note2.duration = 0x48;
|
||||
note2.has_duration_prefix = true;
|
||||
|
||||
auto bytes2 = SpcSerializer::SerializeNote(note2, ¤t_duration);
|
||||
|
||||
// Should only output pitch (duration unchanged)
|
||||
ASSERT_EQ(bytes2.size(), 1);
|
||||
EXPECT_EQ(bytes2[0], 0x8E);
|
||||
}
|
||||
|
||||
TEST_F(SpcSerializerTest, SerializeCommand) {
|
||||
MusicCommand cmd;
|
||||
cmd.opcode = 0xE0;
|
||||
cmd.params = {0x0B, 0, 0}; // SetInstrument(Piano)
|
||||
|
||||
auto bytes = SpcSerializer::SerializeCommand(cmd);
|
||||
|
||||
ASSERT_EQ(bytes.size(), 2);
|
||||
EXPECT_EQ(bytes[0], 0xE0);
|
||||
EXPECT_EQ(bytes[1], 0x0B);
|
||||
}
|
||||
|
||||
TEST_F(SpcSerializerTest, SerializeTrack) {
|
||||
MusicTrack track;
|
||||
|
||||
// SetInstrument(Piano)
|
||||
track.events.push_back(TrackEvent::MakeCommand(0, 0xE0, 0x0B));
|
||||
|
||||
// SetChannelVolume(192)
|
||||
track.events.push_back(TrackEvent::MakeCommand(0, 0xED, 0xC0));
|
||||
|
||||
// Quarter note C2 with duration prefix
|
||||
TrackEvent note_event = TrackEvent::MakeNote(0, 0x8C, 0x48);
|
||||
note_event.note.has_duration_prefix = true;
|
||||
track.events.push_back(note_event);
|
||||
|
||||
// End
|
||||
track.events.push_back(TrackEvent::MakeEnd(72));
|
||||
|
||||
auto bytes = SpcSerializer::SerializeTrack(track);
|
||||
|
||||
// Expected: E0 0B ED C0 48 8C 00
|
||||
ASSERT_GE(bytes.size(), 7);
|
||||
EXPECT_EQ(bytes[0], 0xE0);
|
||||
EXPECT_EQ(bytes[1], 0x0B);
|
||||
EXPECT_EQ(bytes[2], 0xED);
|
||||
EXPECT_EQ(bytes[3], 0xC0);
|
||||
EXPECT_EQ(bytes[4], 0x48);
|
||||
EXPECT_EQ(bytes[5], 0x8C);
|
||||
EXPECT_EQ(bytes.back(), 0x00); // End marker
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BrrCodec Tests
|
||||
// =============================================================================
|
||||
|
||||
class BrrCodecTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
};
|
||||
|
||||
TEST_F(BrrCodecTest, EncodeDecodeRoundtrip) {
|
||||
// Create a simple sine wave
|
||||
std::vector<int16_t> original;
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
double t = i / 64.0 * 2 * 3.14159;
|
||||
original.push_back(static_cast<int16_t>(sin(t) * 10000));
|
||||
}
|
||||
|
||||
// Encode to BRR
|
||||
auto brr = BrrCodec::Encode(original);
|
||||
EXPECT_GT(brr.size(), 0);
|
||||
|
||||
// Decode back
|
||||
auto decoded = BrrCodec::Decode(brr);
|
||||
EXPECT_GT(decoded.size(), 0);
|
||||
|
||||
// Should be similar (BRR is lossy, so allow some error)
|
||||
ASSERT_EQ(decoded.size(), original.size());
|
||||
|
||||
int max_error = 0;
|
||||
for (size_t i = 0; i < original.size(); ++i) {
|
||||
int error = abs(original[i] - decoded[i]);
|
||||
if (error > max_error) max_error = error;
|
||||
}
|
||||
|
||||
// BRR compression should keep error reasonable
|
||||
EXPECT_LT(max_error, 5000); // Allow up to ~15% error
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MusicBank Tests
|
||||
// =============================================================================
|
||||
|
||||
class MusicBankTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
};
|
||||
|
||||
TEST_F(MusicBankTest, GetVanillaSongName) {
|
||||
EXPECT_STREQ(GetVanillaSongName(1), "Title");
|
||||
EXPECT_STREQ(GetVanillaSongName(2), "Light World");
|
||||
EXPECT_STREQ(GetVanillaSongName(12), "Soldier");
|
||||
EXPECT_STREQ(GetVanillaSongName(21), "Boss");
|
||||
EXPECT_STREQ(GetVanillaSongName(0), "Unknown");
|
||||
EXPECT_STREQ(GetVanillaSongName(100), "Unknown");
|
||||
}
|
||||
|
||||
TEST_F(MusicBankTest, GetVanillaSongBank) {
|
||||
EXPECT_EQ(GetVanillaSongBank(1), MusicBank::Bank::Overworld);
|
||||
EXPECT_EQ(GetVanillaSongBank(11), MusicBank::Bank::Overworld);
|
||||
EXPECT_EQ(GetVanillaSongBank(12), MusicBank::Bank::Dungeon);
|
||||
EXPECT_EQ(GetVanillaSongBank(31), MusicBank::Bank::Dungeon);
|
||||
EXPECT_EQ(GetVanillaSongBank(32), MusicBank::Bank::Credits);
|
||||
}
|
||||
|
||||
TEST_F(MusicBankTest, BankMaxSize) {
|
||||
EXPECT_EQ(MusicBank::GetBankMaxSize(MusicBank::Bank::Overworld),
|
||||
kOverworldBankMaxSize);
|
||||
EXPECT_EQ(MusicBank::GetBankMaxSize(MusicBank::Bank::Dungeon),
|
||||
kDungeonBankMaxSize);
|
||||
EXPECT_EQ(MusicBank::GetBankMaxSize(MusicBank::Bank::Credits),
|
||||
kCreditsBankMaxSize);
|
||||
}
|
||||
|
||||
TEST_F(MusicBankTest, CreateNewSong) {
|
||||
MusicBank bank;
|
||||
|
||||
int index = bank.CreateNewSong("Test Song", MusicBank::Bank::Overworld);
|
||||
EXPECT_GE(index, 0);
|
||||
|
||||
auto* song = bank.GetSong(index);
|
||||
ASSERT_NE(song, nullptr);
|
||||
EXPECT_EQ(song->name, "Test Song");
|
||||
EXPECT_EQ(song->bank, static_cast<uint8_t>(MusicBank::Bank::Overworld));
|
||||
EXPECT_TRUE(song->modified);
|
||||
EXPECT_EQ(song->segments.size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MusicBankTest, SpaceCalculation) {
|
||||
MusicBank bank;
|
||||
|
||||
// Empty bank
|
||||
auto space = bank.CalculateSpaceUsage(MusicBank::Bank::Overworld);
|
||||
EXPECT_EQ(space.used_bytes, 0);
|
||||
EXPECT_EQ(space.free_bytes, kOverworldBankMaxSize);
|
||||
EXPECT_EQ(space.total_bytes, kOverworldBankMaxSize);
|
||||
EXPECT_EQ(space.usage_percent, 0.0f);
|
||||
|
||||
// Add a song
|
||||
bank.CreateNewSong("Test", MusicBank::Bank::Overworld);
|
||||
|
||||
space = bank.CalculateSpaceUsage(MusicBank::Bank::Overworld);
|
||||
EXPECT_GT(space.used_bytes, 0);
|
||||
EXPECT_LT(space.free_bytes, kOverworldBankMaxSize);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Direct SPC Bank Mapping Tests
|
||||
// =============================================================================
|
||||
|
||||
class DirectSpcMappingTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
|
||||
// Helper to test bank ROM offset mapping
|
||||
// Note: These match the logic in MusicEditor::GetBankRomOffset
|
||||
uint32_t GetBankRomOffset(uint8_t bank) const {
|
||||
constexpr uint32_t kSoundBankOffsets[] = {
|
||||
0xC8000, // ROM Bank 0 (common) - driver + samples + instruments
|
||||
0xD1EF5, // ROM Bank 1 (overworld songs)
|
||||
0xD8000, // ROM Bank 2 (dungeon songs)
|
||||
0xD5380 // ROM Bank 3 (credits songs)
|
||||
};
|
||||
if (bank < 4) {
|
||||
return kSoundBankOffsets[bank];
|
||||
}
|
||||
return kSoundBankOffsets[0];
|
||||
}
|
||||
|
||||
// Helper to convert song.bank enum to ROM bank
|
||||
uint8_t SongBankToRomBank(uint8_t song_bank) const {
|
||||
// song.bank: 0=overworld, 1=dungeon, 2=credits
|
||||
// ROM bank: 1=overworld, 2=dungeon, 3=credits
|
||||
return song_bank + 1;
|
||||
}
|
||||
|
||||
// Helper to test song index in bank calculation
|
||||
// Matches MusicEditor::GetSongIndexInBank
|
||||
int GetSongIndexInBank(int song_id, uint8_t bank) const {
|
||||
switch (bank) {
|
||||
case 0: // Overworld
|
||||
return song_id - 1; // Songs 1-11 → 0-10
|
||||
case 1: // Dungeon
|
||||
return song_id - 12; // Songs 12-31 → 0-19
|
||||
case 2: // Credits
|
||||
return song_id - 32; // Songs 32-34 → 0-2
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DirectSpcMappingTest, BankRomOffsets) {
|
||||
// ROM Bank 0: Common bank (driver, samples, instruments)
|
||||
EXPECT_EQ(GetBankRomOffset(0), 0xC8000u);
|
||||
|
||||
// ROM Bank 1: Overworld songs
|
||||
EXPECT_EQ(GetBankRomOffset(1), 0xD1EF5u);
|
||||
|
||||
// ROM Bank 2: Dungeon songs
|
||||
EXPECT_EQ(GetBankRomOffset(2), 0xD8000u);
|
||||
|
||||
// ROM Bank 3: Credits songs
|
||||
EXPECT_EQ(GetBankRomOffset(3), 0xD5380u);
|
||||
|
||||
// Invalid bank should return common
|
||||
EXPECT_EQ(GetBankRomOffset(99), 0xC8000u);
|
||||
}
|
||||
|
||||
TEST_F(DirectSpcMappingTest, SongBankToRomBankMapping) {
|
||||
// song.bank 0 (overworld) → ROM bank 1 (0xD1EF5)
|
||||
EXPECT_EQ(SongBankToRomBank(0), 1);
|
||||
EXPECT_EQ(GetBankRomOffset(SongBankToRomBank(0)), 0xD1EF5u);
|
||||
|
||||
// song.bank 1 (dungeon) → ROM bank 2 (0xD8000)
|
||||
EXPECT_EQ(SongBankToRomBank(1), 2);
|
||||
EXPECT_EQ(GetBankRomOffset(SongBankToRomBank(1)), 0xD8000u);
|
||||
|
||||
// song.bank 2 (credits) → ROM bank 3 (0xD5380)
|
||||
EXPECT_EQ(SongBankToRomBank(2), 3);
|
||||
EXPECT_EQ(GetBankRomOffset(SongBankToRomBank(2)), 0xD5380u);
|
||||
}
|
||||
|
||||
TEST_F(DirectSpcMappingTest, OverworldSongIndices) {
|
||||
// Overworld songs: 1-11 (global ID) → 0-10 (bank index)
|
||||
EXPECT_EQ(GetSongIndexInBank(1, 0), 0); // Title
|
||||
EXPECT_EQ(GetSongIndexInBank(2, 0), 1); // Light World
|
||||
EXPECT_EQ(GetSongIndexInBank(11, 0), 10); // File Select
|
||||
}
|
||||
|
||||
TEST_F(DirectSpcMappingTest, DungeonSongIndices) {
|
||||
// Dungeon songs: 12-31 (global ID) → 0-19 (bank index)
|
||||
EXPECT_EQ(GetSongIndexInBank(12, 1), 0); // Soldier
|
||||
EXPECT_EQ(GetSongIndexInBank(13, 1), 1); // Mountain
|
||||
EXPECT_EQ(GetSongIndexInBank(21, 1), 9); // Boss
|
||||
EXPECT_EQ(GetSongIndexInBank(31, 1), 19); // Last Boss
|
||||
}
|
||||
|
||||
TEST_F(DirectSpcMappingTest, CreditsSongIndices) {
|
||||
// Credits songs: 32-34 (global ID) → 0-2 (bank index)
|
||||
EXPECT_EQ(GetSongIndexInBank(32, 2), 0); // Credits 1
|
||||
EXPECT_EQ(GetSongIndexInBank(33, 2), 1); // Credits 2
|
||||
EXPECT_EQ(GetSongIndexInBank(34, 2), 2); // Credits 3
|
||||
}
|
||||
|
||||
TEST_F(DirectSpcMappingTest, BankIndexConsistency) {
|
||||
// Verify bank index is non-negative for all vanilla songs
|
||||
for (int song_id = 1; song_id <= 11; ++song_id) {
|
||||
int index = GetSongIndexInBank(song_id, 0);
|
||||
EXPECT_GE(index, 0) << "Overworld song " << song_id << " should have non-negative index";
|
||||
EXPECT_LE(index, 10) << "Overworld song " << song_id << " should be <= 10";
|
||||
}
|
||||
|
||||
for (int song_id = 12; song_id <= 31; ++song_id) {
|
||||
int index = GetSongIndexInBank(song_id, 1);
|
||||
EXPECT_GE(index, 0) << "Dungeon song " << song_id << " should have non-negative index";
|
||||
EXPECT_LE(index, 19) << "Dungeon song " << song_id << " should be <= 19";
|
||||
}
|
||||
|
||||
for (int song_id = 32; song_id <= 34; ++song_id) {
|
||||
int index = GetSongIndexInBank(song_id, 2);
|
||||
EXPECT_GE(index, 0) << "Credits song " << song_id << " should have non-negative index";
|
||||
EXPECT_LE(index, 2) << "Credits song " << song_id << " should be <= 2";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user