more negative tests
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 10 Jun 2025 15:20:46 +0000 (08:20 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 10 Jun 2025 15:20:46 +0000 (08:20 -0700)
rust/pspp/src/sys/cooked.rs
rust/pspp/src/sys/raw.rs
rust/pspp/src/sys/test.rs
rust/pspp/src/sys/testdata/bad_record_type.expected [new file with mode: 0644]
rust/pspp/src/sys/testdata/bad_record_type.sack [new file with mode: 0644]
rust/pspp/src/sys/testdata/wrong_variable_positions.expected [new file with mode: 0644]
rust/pspp/src/sys/testdata/wrong_variable_positions.sack [new file with mode: 0644]

index 1bbe6aee16a17af6cdaabd1dc2ca9f81807bbe38..cb9de8fde2e936eec7542e7614c263b812c7635a 100644 (file)
@@ -190,6 +190,9 @@ pub enum Error {
     #[error("{0}")]
     InvalidRole(InvalidRole),
 
+    #[error("File header claims {expected} variable positions but {actual} were read from file.")]
+    WrongVariablePositions { actual: usize, expected: usize },
+
     #[error("Details TBD (cooked)")]
     TBD,
 }
@@ -515,6 +518,21 @@ pub fn decode(
     // XXX warn for weird integer format
     // XXX warn for weird floating-point format, etc.
 
+    if let Some(nominal_case_size) = headers.header.nominal_case_size {
+        let n_vars = headers.variable.len();
+        if n_vars != nominal_case_size as usize
+            && headers
+                .integer_info
+                .as_ref()
+                .is_none_or(|info| info.version.0 != 13)
+        {
+            warn(Error::WrongVariablePositions {
+                actual: n_vars,
+                expected: nominal_case_size as usize,
+            });
+        }
+    }
+
     let mut decoder = Decoder {
         encoding,
         n_generated_names: 0,
index c10e1ac81c6f52c53bfb380606755e40a6f0ad7f..3c8ddb9d9a0115227053e8bc8d2ea7519a28cf13 100644 (file)
@@ -510,8 +510,9 @@ impl HeaderRecord<RawString> {
         let layout_code = endian.parse(layout_code);
 
         let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
-        let nominal_case_size =
-            (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
+        let nominal_case_size = (1..i32::MAX as u32 / 16)
+            .contains(&nominal_case_size)
+            .then_some(nominal_case_size);
 
         let compression_code: u32 = endian.parse(read_bytes(r)?);
         let compression = match (magic, compression_code) {
index afd8706e4d860d31a11c6a9721bad75bfd8d00da..3abb9cdc1287b52dc47c928a223352094bee0004 100644 (file)
@@ -127,6 +127,16 @@ fn misplaced_type_4_record() {
     test_sysfile("misplaced_type_4_record");
 }
 
+#[test]
+fn bad_record_type() {
+    test_sysfile("bad_record_type");
+}
+
+#[test]
+fn wrong_variable_positions() {
+    test_sysfile("wrong_variable_positions");
+}
+
 fn test_sysfile(name: &str) {
     let input_filename = Path::new(env!("CARGO_MANIFEST_DIR"))
         .join("src/sys/testdata")
diff --git a/rust/pspp/src/sys/testdata/bad_record_type.expected b/rust/pspp/src/sys/testdata/bad_record_type.expected
new file mode 100644 (file)
index 0000000..93da523
--- /dev/null
@@ -0,0 +1 @@
+At offset 0xd4, unrecognized record type 8.
diff --git a/rust/pspp/src/sys/testdata/bad_record_type.sack b/rust/pspp/src/sys/testdata/bad_record_type.sack
new file mode 100644 (file)
index 0000000..40e0256
--- /dev/null
@@ -0,0 +1,9 @@
+# File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+# Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+# Type 8 record (not a valid type).
+>>8<<;
diff --git a/rust/pspp/src/sys/testdata/wrong_variable_positions.expected b/rust/pspp/src/sys/testdata/wrong_variable_positions.expected
new file mode 100644 (file)
index 0000000..7c01e4d
--- /dev/null
@@ -0,0 +1,20 @@
+File header claims 2 variable positions but 1 were read from file.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
diff --git a/rust/pspp/src/sys/testdata/wrong_variable_positions.sack b/rust/pspp/src/sys/testdata/wrong_variable_positions.sack
new file mode 100644 (file)
index 0000000..1c10ef4
--- /dev/null
@@ -0,0 +1,12 @@
+# File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; >>2<<; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+# Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+# Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+# End of dictionary.
+999; 0;