From eeb97529d525132715674f383b873f019beb05cb Mon Sep 17 00:00:00 2001
From: David Cooper <david@dtcooper.com>
Date: Wed, 31 Jan 2024 11:49:07 -0500
Subject: [PATCH 1/3] Support -9e as an argument for compression

---
 src/pi-gen-config.ts | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/src/pi-gen-config.ts b/src/pi-gen-config.ts
index a011250..552c145 100644
--- a/src/pi-gen-config.ts
+++ b/src/pi-gen-config.ts
@@ -92,16 +92,17 @@ export async function validateConfig(config: PiGenConfig): Promise<void> {
     )
   }
 
-  if (
-    !['none', 'zip', 'gz', 'xz'].includes(
-      config.deployCompression?.toLowerCase()
-    )
-  ) {
+  const deployCompression = config.deployCompression?.toLowerCase()
+  if (!['none', 'zip', 'gz', 'xz'].includes(deployCompression)) {
     throw new Error('compression must be one of ["none", "zip", "gz", "xz"]')
   }
 
-  if (!/^[0-9]$/.test(config.compressionLevel)) {
-    throw new Error('compression-level must be between 0 and 9')
+  if (
+    !/^[0-9]$/.test(config.compressionLevel) &&
+    deployCompression === 'xz' &&
+    config.compressionLevel !== '9e'
+  ) {
+    throw new Error('compression-level must be between 0 and 9 (or 9e for xz)')
   }
 
   const cutCmd = await io.which('cut', true)

From 0bffa6ddc8797a0aacd7b152a3cc3b2c04165879 Mon Sep 17 00:00:00 2001
From: David Cooper <david@dtcooper.com>
Date: Wed, 31 Jan 2024 14:57:55 -0500
Subject: [PATCH 2/3] Fixup

---
 src/pi-gen-config.ts | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/pi-gen-config.ts b/src/pi-gen-config.ts
index 552c145..62fb867 100644
--- a/src/pi-gen-config.ts
+++ b/src/pi-gen-config.ts
@@ -98,9 +98,10 @@ export async function validateConfig(config: PiGenConfig): Promise<void> {
   }
 
   if (
-    !/^[0-9]$/.test(config.compressionLevel) &&
-    deployCompression === 'xz' &&
-    config.compressionLevel !== '9e'
+    !(
+      /^[0-9]$/.test(config.compressionLevel) ||
+      (deployCompression === 'xz' && config.compressionLevel === '9e')
+    )
   ) {
     throw new Error('compression-level must be between 0 and 9 (or 9e for xz)')
   }

From f28c8125ccf8dccca5d90d20d297501d57c9149e Mon Sep 17 00:00:00 2001
From: David Cooper <david@dtcooper.com>
Date: Wed, 31 Jan 2024 15:26:57 -0500
Subject: [PATCH 3/3] Add test

---
 __test__/pi-gen-config.test.ts | 118 ++++++++++++++++++++++++++-------
 1 file changed, 95 insertions(+), 23 deletions(-)

diff --git a/__test__/pi-gen-config.test.ts b/__test__/pi-gen-config.test.ts
index 3b65ead..e2a7731 100644
--- a/__test__/pi-gen-config.test.ts
+++ b/__test__/pi-gen-config.test.ts
@@ -60,33 +60,105 @@ describe('PiGenConfig', () => {
   })
 
   it.each([
-    ['imgName', ''],
-    ['release', 'foo'],
-    ['deployCompression', 'bzip2'],
-    ['compressionLevel', '15'],
-    ['localeDefault', 'en_DE.UTF-42'],
-    ['targetHostname', undefined],
-    ['keyboardKeymap', ''],
-    ['keyboardLayout', undefined],
-    ['timezoneDefault', 'Europe/Munich'],
-    ['firstUserName', ''],
-    ['wpaEssid', '0'.repeat(33)],
-    ['wpaPassword', '12345'],
-    ['wpaPassword', '0'.repeat(64)],
-    ['setfcap', '0'],
-    ['stageList', []],
-    ['stageList', ['foo']],
-    ['stageList', [tmp.fileSync().name]],
-    ['enableNoobs', 'yes'],
-    ['exportLastStageOnly', 'no']
+    ['imgName', '', 'image-name must not be empty'],
+    [
+      'release',
+      'foo',
+      'release must be one of ["bookworm", "bullseye", "jessie", "stretch", "buster", "testing"]'
+    ],
+    [
+      'deployCompression',
+      'bzip2',
+      'compression must be one of ["none", "zip", "gz", "xz"]'
+    ],
+    [
+      'compressionLevel',
+      '15',
+      'compression-level must be between 0 and 9 (or 9e for xz)'
+    ],
+    [
+      'localeDefault',
+      'en_DE.UTF-42',
+      'locale is not included in the list of supported locales (retrieved from /usr/share/i18n/SUPPORTED)'
+    ],
+    ['targetHostname', undefined, 'hostname must not be empty'],
+    ['keyboardKeymap', '', 'keyboard-keymap must not be empty'],
+    ['keyboardLayout', undefined, 'keyboard-layout must not be empty'],
+    [
+      'timezoneDefault',
+      'Europe/Munich',
+      'timezone is not included in output of "timedatectl list-timezones"'
+    ],
+    ['firstUserName', '', 'username must not be empty'],
+    [
+      'wpaEssid',
+      '0'.repeat(33),
+      'wpa-essid must not be longer than 32 characters'
+    ],
+    [
+      'wpaPassword',
+      '12345',
+      'wpa-password must be between 8 and 63 characters (or unset)'
+    ],
+    [
+      'wpaPassword',
+      '0'.repeat(64),
+      'wpa-password must be between 8 and 63 characters (or unset)'
+    ],
+    ['setfcap', '0', 'setfcap should only be set to "1", nothing else'],
+    ['stageList', [], 'stage-list must not be empty'],
+    [
+      'stageList',
+      ['foo'],
+      'stage-list must contain valid pi-gen stage names "stage[0-5]" and/or valid directories'
+    ],
+    [
+      'stageList',
+      [tmp.fileSync().name],
+      'stage-list must contain valid pi-gen stage names "stage[0-5]" and/or valid directories'
+    ],
+    [
+      'enableNoobs',
+      'yes',
+      'enable-noobs must be either set to "true" or "false", was: yes'
+    ],
+    [
+      'exportLastStageOnly',
+      'no',
+      'export-last-stage-only must be either set to "true" or "false", was: no'
+    ]
   ])(
     'rejects %s with invalid value %s',
-    async (property: string, value: any) => {
-      const piGenConfig = {...DEFAULT_CONFIG}
+    async (property: string, value: any, error: string) => {
+      const piGenConfig = {
+        ...DEFAULT_CONFIG,
+        stageList: ['stage0', 'stage1', 'stage2']
+      }
+      expect(await validateConfig(piGenConfig)).toBeUndefined()
+
       piGenConfig[property as keyof PiGenConfig] = value
+      expect(async () => await validateConfig(piGenConfig)).rejects.toThrow(
+        error
+      )
+    }
+  )
+
+  it('should work with compressionLevel properly', async () => {
+    const piGenConfig = {
+      ...DEFAULT_CONFIG,
+      stageList: ['stage0', 'stage1', 'stage2'],
+      deployCompression: 'xz',
+      compressionLevel: '9e'
+    }
+
+    expect(await validateConfig(piGenConfig)).toBeUndefined()
+    for (const deployCompression of ['none', 'zip', 'gz']) {
+      piGenConfig.deployCompression = deployCompression
       await expect(
         async () => await validateConfig(piGenConfig)
-      ).rejects.toThrow()
+      ).rejects.toThrow(
+        'compression-level must be between 0 and 9 (or 9e for xz)'
+      )
     }
-  )
+  })
 })