Skip to content

Commit

Permalink
feat(fix): error handling (#3)
Browse files Browse the repository at this point in the history
* fix bug in error handling

* CI runs on multiple OSs
  • Loading branch information
guuzaa authored Sep 14, 2024
1 parent 3720c29 commit 4e7fb8a
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 47 deletions.
12 changes: 8 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ env:

jobs:
build:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4

Expand All @@ -23,12 +27,12 @@ jobs:
- name: Check formatting
run: cargo fmt -- --check

- name: Build
- name: Build on ${{ matrix.os }}
run: cargo build --verbose

- name: Run tests
- name: Run tests on ${{ matrix.os }}
run: cargo test --verbose

- name: Run clippy
- name: Run clippy on ${{ matrix.os }}
run: cargo clippy -- -D warnings

39 changes: 3 additions & 36 deletions src/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use clap::{Parser, ValueEnum};
use std::fs::File;
use std::io::{self, BufReader};
use std::io;

use crate::input_processor::{print_counts, process_input, CountOptions, InputCounts};
use crate::input_processor::{process_inputs, CountOptions};

#[derive(Parser)]
#[command(author, version, about = "A simple count program by Rust and Cursor")]
Expand Down Expand Up @@ -78,37 +77,5 @@ impl Cli {

pub fn run() -> io::Result<()> {
let (cli, options) = Cli::parse_args();

let mut stdout = io::stdout();
let mut total_counts = InputCounts::default();
let mut file_count = 0;

if cli.files.is_empty() {
let stdin = io::stdin();
let mut reader = BufReader::new(stdin.lock());
if let Err(err) = process_input(&mut reader, &mut stdout, &options, None) {
eprintln!("Error processing stdin: {}", err);
}
} else {
for filename in &cli.files {
match File::open(filename) {
Ok(mut file) => {
match process_input(&mut file, &mut stdout, &options, Some(filename)) {
Ok(counts) => {
total_counts += counts;
file_count += 1;
}
Err(err) => eprintln!("Error processing file '{}': {}", filename, err),
}
}
Err(err) => eprintln!("Error opening file '{}': {}", filename, err),
}
}
}

if file_count > 1 {
print_counts(&mut stdout, &total_counts, &options, Some("total"))?;
}

Ok(())
process_inputs(&cli.files, &mut io::stdout(), &options)
}
58 changes: 55 additions & 3 deletions src/input_processor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cmd::TokenizerModel;
use std::io::{self, Read, Write};
use std::fs::File;
use std::io::{self, BufReader, Read, Write};
use tiktoken_rs::{cl100k_base, o200k_base, p50k_base, p50k_edit, r50k_base};

pub struct CountOptions {
Expand Down Expand Up @@ -36,7 +37,58 @@ impl std::ops::AddAssign for InputCounts {
}
}

pub fn process_input<R, W>(
pub fn process_inputs<W>(
files: &Vec<String>,
writer: &mut W,
options: &CountOptions,
) -> io::Result<()>
where
W: Write,
{
let mut total_counts = InputCounts::default();
let mut file_count = 0;
let mut error_count = 0;

if files.is_empty() {
let stdin = io::stdin();
let mut reader = BufReader::new(stdin.lock());
if let Err(err) = process_input(&mut reader, writer, options, None) {
error_count += 1;
eprintln!("tc: Error processing stdin: {}", err);
}
} else {
for filename in files {
match File::open(filename) {
Ok(mut file) => match process_input(&mut file, writer, options, Some(filename)) {
Ok(counts) => {
total_counts += counts;
}
Err(err) => {
error_count += 1;
eprintln!("tc: Error processing file '{}': {}", filename, err)
}
},
Err(err) => {
error_count += 1;
eprintln!("tc: Error opening file '{}': {}", filename, err)
}
}
file_count += 1;
}
}

if file_count > 1 {
print_counts(writer, &total_counts, options, Some("total"))?;
}

if error_count > 0 {
Err(io::Error::new(io::ErrorKind::Other, ""))
} else {
Ok(())
}
}

fn process_input<R, W>(
reader: &mut R,
writer: &mut W,
options: &CountOptions,
Expand Down Expand Up @@ -102,7 +154,7 @@ fn count_input(buffer: &[u8], options: &CountOptions) -> InputCounts {
}
}

pub fn print_counts<W: Write>(
fn print_counts<W: Write>(
writer: &mut W,
counts: &InputCounts,
options: &CountOptions,
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ mod cmd;
mod input_processor;

fn main() {
if let Err(err) = cmd::run() {
eprintln!("Error: {}", err);
if cmd::run().is_err() {
process::exit(1);
}
}
42 changes: 40 additions & 2 deletions tests/tc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ fn test_non_existent_file() {
let mut cmd = Command::cargo_bin("tc").unwrap();
cmd.arg("non_existent_file.txt")
.assert()
.success()
.stderr(predicate::str::contains("Error opening file"));
.failure()
.stderr(predicate::str::contains("tc: Error opening file"));
}

#[test]
Expand Down Expand Up @@ -107,3 +107,41 @@ fn test_different_tokenizer_model() {
.success()
.stdout(" 1 2 13 4\n");
}

#[test]
fn test_error_code_without_termination() {
let dir = tempdir().unwrap();
let existing_file1 = dir.path().join("existing1.txt");
let existing_file2 = dir.path().join("existing2.txt");
let non_existent_file = dir.path().join("non_existent.txt");

// Create existing files
let mut file1 = File::create(&existing_file1).unwrap();
writeln!(file1, "This is an existing file.").unwrap();

let mut file2 = File::create(&existing_file2).unwrap();
writeln!(file2, "This is another existing file.").unwrap();

let mut cmd = Command::cargo_bin("tc").unwrap();
cmd.arg(&existing_file1)
.arg(&non_existent_file)
.arg(&existing_file2)
.assert()
.failure()
.code(1) // Expect an error code of 1
.stdout(predicate::str::contains(" 1 5 26 7")) // Output for first existing file
.stderr(predicate::str::contains("tc: Error opening file")) // Error message for non-existent file
.stdout(predicate::str::contains(" 1 5 31 7")) // Output for second existing file
.stdout(predicate::str::contains(
" 2 10 57 14 total",
)); // Total count

// Verify that the process didn't terminate early by checking if it processed both existing files
let output = cmd.output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("existing1.txt"));
assert!(stdout.contains("existing2.txt"));
assert!(stdout.contains("total"));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("non_existent.txt"));
}

0 comments on commit 4e7fb8a

Please sign in to comment.