Использовать общий итератор версии прошивки
Убрать повторное увеличение версии из проектной обёртки. Проверять прямое подключение templates и вызов через обёртку в CCS. Сохранить текущий номер прошивки 1.0.5 и уточнить документацию.
This commit is contained in:
@@ -81,16 +81,20 @@ class BuildStepsTest(unittest.TestCase): # Проверяет контракт
|
||||
|
||||
def test_carry_and_exhaustion(self): # Проверяет обе границы переноса и запрет переполнения полного номера.
|
||||
for previous, expected in (([1, 9, 999], [1, 10, 0]), ([1, 255, 999], [2, 0, 0])): # Эталонные значения заданы независимо от production-счётчика.
|
||||
self.assertEqual(builder.next_version(previous), expected) # Проверяет перенос из patch в minor и из minor в major.
|
||||
self.settings["version"] = list(previous) # Передаёт граничный номер общему итератору через штатный JSON проекта.
|
||||
self.save_settings() # Сохраняет исходный номер только во временном проекте проверки.
|
||||
self.assertEqual(builder.prepare(self.config, self.build_dir)["version"], expected) # Проверяет перенос через реальную цепочку проектный BAT → общий precompile.
|
||||
self.settings["version"] = [255, 255, 999] # Задаёт последний допустимый номер контракта.
|
||||
self.save_settings() # Устанавливает границу в сохраняемой конфигурации.
|
||||
previous = self.config.read_bytes() # Полное переполнение не должно портить исходный JSON.
|
||||
with self.assertRaises(ValueError): builder.prepare(self.config, self.build_dir) # Больше допустимых номеров нет, поэтому prebuild обязан остановиться.
|
||||
with self.assertRaises(subprocess.CalledProcessError): builder.prepare(self.config, self.build_dir) # Общий precompile отклоняет переполнение и передаёт проектной обёртке ненулевой код процесса.
|
||||
self.assertEqual(self.config.read_bytes(), previous) # Проверяет отсутствие сброса версии к нулю или частичной записи.
|
||||
|
||||
def test_failure_consumes_number_and_bat_returns_error(self): # Сохраняет правило занятых номеров при неудачной сборке и передачу ошибки CCS.
|
||||
with patch.object(builder.subprocess, "run", side_effect=subprocess.CalledProcessError(7, "precompile.bat")): # Моделирует отказ общего генератора после резервирования версии.
|
||||
with self.assertRaises(subprocess.CalledProcessError): builder.prepare(self.config, self.build_dir) # Ошибка должна дойти до вызывающего процесса.
|
||||
self.build_dir.mkdir() # Готовит каталог только временного проекта для воспроизведения отказа записи заголовка.
|
||||
(self.build_dir / "generated").write_text("blocked", encoding="utf-8") # Файл вместо каталога generated вызывает отказ общего генератора после резервирования номера.
|
||||
result = subprocess.run(["cmd.exe", "/d", "/c", "call", str(self.project / "firmware_build.bat"), "prepare", "--build-dir", str(self.build_dir)], cwd=ROOT, capture_output=True) # Реальный BAT проверяет передачу ошибки templates без подмены процесса, владеющего счётчиком.
|
||||
self.assertNotEqual(result.returncode, 0) # Неудачная генерация заголовка обязана остановить pre-build.
|
||||
self.assertEqual(json.loads(self.config.read_text(encoding="utf-8"))["version"], [1, 0, 1]) # Следующая попытка не должна повторять номер неудачной сборки.
|
||||
result = subprocess.run(["cmd.exe", "/d", "/c", "call", str(self.project / "firmware_build.bat"), "build"], cwd=ROOT, capture_output=True) # Намеренно пропускает обязательные аргументы CLI через настоящий BAT.
|
||||
self.assertNotEqual(result.returncode, 0) # BAT не должен маскировать ошибку Python успешным завершением.
|
||||
@@ -156,14 +160,19 @@ class BuildStepsTest(unittest.TestCase): # Проверяет контракт
|
||||
builder.verify_package(self.project.parent / "images copy" / image.name, metadata) # Проверяет SHA-256 и метаданные дополнительной копии.
|
||||
self.assertEqual(json.loads(self.config.read_text(encoding="utf-8"))["version"], [1, 0, 1]) # Postbuild не увеличивает номер повторно после prebuild.
|
||||
|
||||
def test_ccs_uses_bat_in_both_configurations(self): # Не допускает возврат к длинным проектным Python-командам в CCS.
|
||||
def test_ccs_prebuild_increments_in_both_configurations(self): # Проверяет фактический итератор и при прямом подключении templates, и через проектную обёртку CCS.
|
||||
configurations = ET.parse(PROJECT / ".cproject").findall("./storageModule/cconfiguration/storageModule/configuration") # Проверяет реальные настройки проекта.
|
||||
self.assertEqual({item.get("name") for item in configurations}, {"Debug", "Release"}) # Требует обнаружения обеих конфигураций.
|
||||
for configuration in configurations: # Проверяет подключение обоих шагов независимо от активной конфигурации IDE.
|
||||
for field, command in (("prebuildStep", "prepare"), ("postbuildStep", "build")): # Оба этапа должны запускаться через один переносимый BAT.
|
||||
self.assertIn(f'firmware_build.bat" {command} ', configuration.get(field)) # Проверяет команду и единый BAT-файл.
|
||||
self.assertNotIn("python", configuration.get(field)) # Выбор интерпретатора и путь к сценарию остаются внутри BAT.
|
||||
self.assertNotIn("SRC_ROOT", configuration.get(field)) # Шаги CCS больше не зависят от структуры репозитория исходного изделия.
|
||||
self.settings["version"] = [1, 0, 4] # Воспроизводит рабочий номер, на котором прямое подключение templates перестало увеличивать версию.
|
||||
self.save_settings() # Не меняет настоящий JSON и не занимает номера пользовательских прошивок.
|
||||
for configuration, expected in zip(configurations, ([1, 0, 5], [1, 0, 6])): # Два запуска с одним JSON должны увеличивать номер ровно по одному разу.
|
||||
build_dir = self.build_dir / configuration.get("name") # Каждая конфигурация получает собственные generated, как при сборке в IDE.
|
||||
command = configuration.get("prebuildStep").rstrip(";").replace("${PROJECT_LOC}", str(self.project)).replace("${BuildDirectory}", str(build_dir)) # Подставляет макросы CCS и удаляет завершающий разделитель списка команд IDE.
|
||||
result = subprocess.run(command, cwd=ROOT, capture_output=True) # Выполняет команду из настоящего XML через cmd с путями, содержащими пробелы.
|
||||
self.assertEqual(result.returncode, 0, repr(result.stdout) + repr(result.stderr)) # Показывает диагностику фактического BAT, если подключение templates неработоспособно.
|
||||
self.assertEqual(json.loads(self.config.read_text(encoding="utf-8"))["version"], expected) # Проверяет сохраняемый счётчик после прямого вызова и обёртки без двойного увеличения.
|
||||
self.assertEqual(json.loads((build_dir / "generated/firmware_identity.json").read_text(encoding="utf-8"))["version"], expected) # Паспорт компиляции обязан содержать тот же номер, который зарезервирован в JSON.
|
||||
self.assertIn(f"#define FIRMWARE_VERSION_PATCH {expected[2]}U", (build_dir / "generated/firmware_identity.h").read_text(encoding="utf-8")) # Проверяет, что компилятор получит обновлённую версию, а не только новый manifest.
|
||||
|
||||
|
||||
if __name__ == "__main__": unittest.main() # Любое нарушение версии, переносимости или защиты BIN возвращает ненулевой код.
|
||||
|
||||
Reference in New Issue
Block a user