Back to Repositories

Validating Cross-Platform AR Archive Parsing in Telegram

This test suite validates the parsing and handling of AR archive files across different operating systems (Linux, macOS, Windows) in the BoringSSL library used by Telegram. It ensures correct extraction and verification of object files from static libraries.

Test Coverage Overview

The test suite provides comprehensive coverage for AR archive parsing functionality across multiple platforms.

Key areas tested include:
  • File content extraction and verification
  • Platform-specific archive formats (Linux .a, macOS .a, Windows .lib)
  • Object file naming conventions
  • Padding handling for macOS archives

Implementation Analysis

The testing approach utilizes Go’s native testing framework with table-driven tests, allowing for systematic validation of AR parsing across different platforms.

Key implementation patterns include:
  • Structured test cases with platform-specific expectations
  • File path handling with testdata directory configuration
  • Binary content comparison with padding accommodation
  • Detailed error reporting for content mismatches

Technical Details

Testing infrastructure includes:
  • Go testing package for test execution
  • File I/O operations for archive handling
  • Byte-level comparison utilities
  • Platform-specific test data organization
  • Command-line flags for test data directory configuration

Best Practices Demonstrated

The test implementation showcases several testing best practices:

  • Modular test case structure using arTest type
  • Comprehensive platform coverage
  • Proper cleanup with deferred file closing
  • Detailed error messages for debugging
  • Flexible test data path configuration
  • Systematic validation of both expected and unexpected content

drklo/telegram

TMessagesProj/jni/boringssl/util/ar/ar_test.go

            
// Copyright (c) 2018, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

package ar

import (
	"bytes"
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

var testDataDir = flag.String("testdata", "testdata", "The path to the test data directory.")

type arTest struct {
	name string
	in   string
	out  map[string]string
	// allowPadding is true if the contents may have trailing newlines at end.
	// On macOS, ar calls ranlib which pads all inputs up to eight bytes with
	// newlines. Unlike ar's native padding up to two bytes, this padding is
	// included in the size field, so it is not removed when decoding.
	allowPadding bool
}

func (test *arTest) Path(file string) string {
	return filepath.Join(*testDataDir, test.name, file)
}

func removeTrailingNewlines(in []byte) []byte {
	for len(in) > 0 && in[len(in)-1] == '\n' {
		in = in[:len(in)-1]
	}
	return in
}

var arTests = []arTest{
	{
		"linux",
		"libsample.a",
		map[string]string{
			"foo.c.o": "foo.c.o",
			"bar.cc.o": "bar.cc.o",
		},
		false,
	},
	{
		"mac",
		"libsample.a",
		map[string]string{
			"foo.c.o": "foo.c.o",
			"bar.cc.o": "bar.cc.o",
		},
		true,
	},
	{
		"windows",
		"sample.lib",
		map[string]string{
			"CMakeFiles\\sample.dir\\foo.c.obj": "foo.c.obj",
			"CMakeFiles\\sample.dir\\bar.cc.obj": "bar.cc.obj",
		},
		false,
	},
}

func TestAR(t *testing.T) {
	for _, test := range arTests {
		t.Run(test.name, func(t *testing.T) {
			in, err := os.Open(test.Path(test.in))
			if err != nil {
				t.Fatalf("opening input failed: %s", err)
			}
			defer in.Close()

			ret, err := ParseAR(in)
			if err != nil {
				t.Fatalf("reading input failed: %s", err)
			}

			for file, contentsPath := range test.out {
				expected, err := ioutil.ReadFile(test.Path(contentsPath))
				if err != nil {
					t.Fatalf("error reading %s: %s", contentsPath, err)
				}
				got, ok := ret[file]
				if test.allowPadding {
					got = removeTrailingNewlines(got)
					expected = removeTrailingNewlines(got)
				}
				if !ok {
					t.Errorf("file %s missing from output", file)
				} else if !bytes.Equal(got, expected) {
					t.Errorf("contents for file %s did not match", file)
				}
			}

			for file, _ := range ret {
				if _, ok := test.out[file]; !ok {
					t.Errorf("output contained unexpected file %q", file)
				}
			}
		})
	}
}